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 プログラムにエントリーポイントは必須ではありませんが、
エントリーポイントは GPUProgrammableStage
の作成に必要なため、そのようなプログラムを API で実行することはできません。
シェーダーステージを実行するとき、実装は次の処理を行います。
-
モジュールスコープで宣言された定数の値を計算します。
-
リソースを シェーダーのリソースインターフェイス内の変数にバインドし、 実行中にシェーダーがそれらのリソースの内容を利用できるようにします。
-
その他のモジュールスコープ変数のためにメモリを割り当て、 指定された初期値をそのメモリに設定します。
-
エントリーポイントの仮引数が存在する場合は、シェーダーステージの入力を設定します。
-
エントリーポイントの戻り値が存在する場合は、シェーダーステージの出力に接続します。
-
その後、エントリーポイントを呼び出します。
WGSL プログラムは、次の要素で構成されます。
-
モジュールレベルの動作制御を指定するディレクティブ。
-
実行動作を指定する関数。
-
宣言または実行可能な動作の単位である文。
-
純粋な数学的値のテキスト表現であるリテラル。
-
それぞれが特定の時点で計算される値に名前を与える定数。
-
それぞれが値を保持するメモリに名前を与える変数。
-
それぞれが一連の値を組み合わせて結果値を生成する式。
-
それぞれが次の内容を記述する型。
-
値の集合。
-
サポートされる式に対する制約。
-
それらの式のセマンティクス。
-
-
オブジェクトを変更し、次のような追加情報を指定する属性。
-
エントリー ポイントに対するインターフェイスの指定。
-
診断フィルターの指定。
-
注記: 現在、WGSL プログラムは単一の WGSL モジュールから構成されます。
WGSL は命令型言語です。動作は、実行する文のシーケンスとして指定されます。 文では、次のことを行えます。
-
変数の内容を変更する。
-
構造化プログラミング構文を使用して実行順序を変更する。
-
上記の動作の一部として式を評価し、値を計算する。
WGSL は静的型付け言語です。特定の式によって計算される各値は、 プログラムソースを調べることだけで決定される特定の型に属します。
WGSL には、ブール値および数値 (整数と浮動小数点数)を記述する型があります。 これらの型は、複合型 (ベクトル、行列、 配列、および構造体)に集約できます。 WGSL には、固有の操作を提供する特殊な型(例: アトミック型)があります。 WGSL では、メモリに格納できる型をメモリビューとして記述します。 WGSL は、一般的に使用されるレンダリング型を テクスチャーおよびサンプラーの形式で提供します。 これらの型には、グラフィックスレンダリングで一般的に提供される GPU ハードウェアの機能を公開する 組み込み関数が関連付けられています。
WGSL の暗黙的な変換および昇格は非常に限定されています。 引数として関数呼び出しに渡される抽象型およびバッファーポインターからの暗黙的な変換と昇格のみを提供します。 ある具象数値型またはブール型の値から別の型への変換には、 明示的な変換、 値コンストラクター、または ビットの 再解釈が必要です。ただし、WGSL はスカラー型から ベクトル型への昇格について、限定的な機能を提供します。 これは、複合型にも適用されます。
シェーダーステージの作業は1つ以上の呼び出しに分割されます。 各呼び出しは、わずかに異なる条件下でエントリーポイントを実行します。 シェーダーステージ内の呼び出しは、特定の変数へのアクセスを共有します。
-
ステージ内のすべての呼び出しは、シェーダーインターフェイス内のリソースを共有します。
-
コンピュート シェーダーでは、同じ ワークグループ内の呼び出しが、 ワークグループアドレス空間内の変数を共有します。 異なるワークグループ内の呼び出しは、それらの変数を共有しません。
ただし、呼び出しは、同等の呼び出しから区別するための識別値を提供する組み込み入力を含む、 異なるシェーダーステージ入力の集合に作用します。 各呼び出しは、プライベートおよび関数アドレス空間内の 変数という形式で、独立した固有のメモリ空間を持ちます。
シェーダーステージ内の呼び出しは並行して実行され、多くの場合は並列に実行されます。 シェーダー作成者は、シェーダーステージ内の呼び出しの動的な動作が 次の条件を満たすようにする責任があります。
-
テクスチャーサンプリングおよび制御バリアを含む、特定のプリミティブ操作の 均一性要件を満たす。
-
データ競合を回避するため、共有変数への競合する可能性のあるアクセスを調整する。
WGSL では、特定の機能について複数の動作が許容されることがあります。 異なる実装が異なる動作を示す可能性があるため、これは移植性上の危険となります。 WGSL の設計は、そのような場合を最小限に抑えることを目指していますが、実現可能性と、 幅広いデバイスで高いパフォーマンスを達成するという目標による制約を受けます。
動作 要件は、WGSL プログラムを処理または実行するときに実装が 行うアクションです。プログラマーとの契約における 実装の義務を記述します。 この仕様では、これらの義務が明白でない可能性がある場合に、それらを明示的に記述します。
1.2. 構文表記
次の構文表記は、WGSL の構文文法の規約を記述します。
-
規則の両側にある斜体テキストは、構文規則を示します。
-
規則の右辺にある、一重引用符(')で始まり終わる太字の等幅テキストは、 キーワードおよびトークンを示します。
-
通常のテキスト内のコロン(:)は、構文規則を登録します。
-
通常のテキスト内の縦棒(|)は、選択肢を示します。
-
通常のテキスト内の疑問符(?)は、直前のキーワード、トークン、規則、 またはグループが0回または1回出現すること(任意であること)を示します。
-
通常のテキスト内のアスタリスク(*)は、直前のキーワード、トークン、規則、またはグループが 0回以上出現することを示します。
-
通常のテキスト内のプラス(+)は、直前のキーワード、トークン、規則、またはグループが 1回以上出現することを示します。
-
通常のテキスト内の左丸括弧(()と右丸括弧 ())の対応する組は、要素のグループを示します。
1.3. 数学用語と表記
角度:
-
慣例により、角度はラジアンで測定されます。
-
角度を測定するための基準半直線は、原点 (0,0) から (+∞,0) に向かう半直線です。
-
比較対象の半直線と基準半直線がなす角度を θ とします。 比較対象の半直線が反時計回りに移動すると、θ は増加します。
-
完全な円には 2 π ラジアンがあります。
-
例:
-
角度 0 は原点から右方向の (1,0) を指します
-
角度 2π は原点から右方向の (1,0) を指します
-
角度 π/4 は原点から点 (1,1) を指します
-
角度 π/2 は原点から点 (0,1) を指します
-
角度 π は原点から点 (-1,0) を指します
-
角度 (3/2)π は原点から点 (0,-1) を指します
-
双曲角は、 従来の意味での角度ではなく、単位を持たない面積です。 具体的には、次のとおりです。
-
x > 0 に対する双曲線 x2 - y2 = 1 を考えます。
-
R を、原点から双曲線上の点 (x, y) までの半直線とします。
-
a を、R、x 軸、および双曲線の曲線 自体によって囲まれる面積の2倍とします。
-
R が x 軸より上にある場合は a を正、 下にある場合は負とみなします。
このとき、面積 a は、x が a の双曲線余弦となり、 y が a の双曲線正弦となるような双曲角です。
正の無限大は +∞ で表され、すべての実数より真に大きい一意の値です。
負の無限大は −∞ で表され、すべての実数より真に小さい一意の値です。
拡張実数 (アフィン拡張実数とも呼ばれる)は、実数に +∞ と −∞ を加えた集合です。 コンピューターは、両方の無限大の値を含む拡張実数を近似的に表現するために 浮動小数点型を使用します。 § 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 は、 k ≤ x < k+1 を満たす一意の整数です
天井 式は、拡張実数 x に対して次のように定義されます。
-
⌈ +∞ ⌉ = +∞
-
⌈ −∞ ⌉ = −∞
-
実数 x について、⌈x⌉ = k。ここで k は、 k-1 < x ≤ k を満たす一意の整数です
truncate 関数は、 拡張実数 x に対して次のように定義されます。
-
truncate(+∞) = +∞
-
truncate(−∞) = −∞
-
実数 x について、その絶対値が x の絶対値以下である 最も近い整数を計算します。
-
x ≥ 0 の場合は truncate(x) = ⌊x⌋、それ以外の x < 0 の場合は ⌈x⌉。
-
roundUp 関数は、 正の整数 k および n に対して次のように定義されます。
-
roundUp(k, n) = ⌈n ÷ k⌉ × k
roundDown 関数は、 正の整数 k および n に対して次のように定義されます。
-
roundDown(k, n) = ⌊n ÷ k⌋ × k
転置は、 c 列 r 行の行列 A の行を AT の列としてコピーすることによって形成される、r 列 c 行の行列 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のためにコンパイルされるエントリーポイントの シェーダーに存在するコードについてのみ発生します。 -
動的エラーは、 シェーダーの実行中に発生するエラーです。 これらのエラーは、検出できる場合とできない場合があります。
注記: たとえば、データ競合は検出できない場合があります。
各要件は、最も早い機会に必ず検査されます。 つまり、次のようになります。
-
シェーダー作成時に検出可能な要件を満たさなかった場合、シェーダー作成 エラーとなります。
-
パイプライン作成時には検出できるものの、それより前には検出できない要件を満たさなかった場合、 パイプライン作成エラーとなります。
文脈から明らかでない場合、この仕様では、 特定の要件を満たさなかったことによって シェーダー作成エラー、パイプライン作成エラー、または動的エラーのいずれが発生するかを示します。
エラーの結果は次のとおりです。
-
シェーダー作成エラーまたはパイプライン作成エラーを含む WGSL モジュールは、 パイプラインに組み込まれないため、 実行されません。
-
動的エラーが 発生した場合:
-
-
WGSL モジュール内の変数にバインドされたリソースの任意の部分、および
-
WGSL モジュール内で宣言されたその他の変数。
-
それ以外については、プログラムがこの仕様の残りの部分で説明されているように動作しない場合があります。 注記: これらの影響は非局所的である可能性があります。
-
2.3. 診断
実装は、シェーダーモジュール作成時またはパイプライン作成時に 診断を生成できます。 診断は、 アプリケーション作成者のために実装が生成するメッセージです。
特定の条件が満たされたときに診断が作成、すなわち トリガーされます。その条件は トリガー規則と呼ばれます。 ソーステキスト内でその条件が満たされた場所は、ソーステキスト内の点または範囲として表され、 トリガーロケーションと呼ばれます。
診断には、次の プロパティがあります。
-
重大度。
診断の重大度は、重要度が高いものから低いものの順に、次のいずれかになります。
- error
-
診断はエラーです。 これは、シェーダー作成エラーまたはパイプライン作成 エラーに対応します。
- warning
-
診断は、アプリケーション開発者が注意を払うに値するものの、エラーではない異常を記述します。
- info
-
診断は、アプリケーション開発者が注意を払うに値するものの、エラーでも警告でもない注目すべき状態を記述します。
- off
-
診断は無効です。アプリケーションには伝達されません。
トリガー規則の名前は、次のいずれかです。
-
ピリオド
'.'(U+002E) で区切られた2つのdiagnostic_name_tokenトークン。
2.3.1. 診断処理
トリガーされた診断は、次のように必ず処理されます。
-
各診断 D について、D のトリガー ロケーションを含む最小の影響範囲を持ち、同じトリガー規則を持つ診断フィルターを見つけます。
-
そのようなフィルターが存在する場合、それを D に適用し、D の重大度を更新します。
-
それ以外の場合、D は変更されません。
-
-
重大度が off の診断を破棄します。
-
残りの診断のうち少なくとも1つの DI の重大度が info である場合:
-
同じトリガー規則を持つその他の info 診断は、元の診断 DI のみを残して 破棄してもよい。
-
-
残りの診断のうち少なくとも1つの DW の重大度が warning である場合:
-
残りの診断のうち少なくとも1つが error の重大度を持つ場合:
-
error の重大度を持つその他の診断を含め、 その他の診断を破棄してもよい。
-
プログラムエラーが 生成されます。
-
診断がシェーダーモジュール作成時にトリガーされた場合、 エラーはシェーダー作成エラーです。
-
診断がパイプライン作成時にトリガーされた場合、 エラーはパイプライン作成エラーです。
-
-
-
シェーダーモジュール作成時に処理している場合、残りの診断は、 WebGPU
GPUCompilationInfoオブジェクトのmessagesメンバーに設定されます。 -
パイプライン作成時に処理している場合、error 診断は、
GPUProgrammableStageの検証時に WebGPU 検証の失敗を引き起こします。
注記: この規則により、実装はエラーが検出されるとすぐに WGSL モジュールの処理を停止できます。 さらに、特定の種類の警告の解析は最初の警告で停止でき、 特定の種類の info 診断の解析は最初の発生時に停止できます。 WGSL は、異なる種類の解析を実行する順序や、単一の解析内での順序を指定しません。 したがって、同じ WGSL モジュールについて、異なる実装が同じ重大度を持つ異なる診断インスタンスを 報告する可能性があります。
2.3.2. フィルター可能なトリガー規則
ほとんどの診断は、無条件に WebGPU アプリケーションへ報告されます。 一部の種類の診断は、そのトリガー規則を指定することなどにより、フィルタリングできます。 次の表に、フィルタリング可能な標準のトリガー規則一式を示します。
| フィルタリング可能なトリガー規則 | デフォルトの重要度 | トリガー位置 | 説明 |
|---|---|---|---|
| derivative_uniformity | エラー | 導関数を計算する組み込み関数の 呼び出し 箇所の位置。 すなわち、次のいずれかの呼び出し位置です。 |
組み込み関数の呼び出しが導関数を計算するものの、一様性解析では、
その呼び出しが一様な制御フロー内で行われることを証明できない場合。
§ 15.2 一様性を参照してください。 |
| subgroup_uniformity | エラー | サブグループまたはクアッドの 組み込み関数の呼び出し 箇所の位置。 |
サブグループまたはクアッドの組み込み関数が呼び出されるものの、一様性解析では、
その呼び出しが一様な制御フロー内で行われることを証明できない場合。
さらに、次のパラメーター値が一様であることを一様性解析で証明できない場合。
§ 15.2 一様性を参照してください。 |
単一の診断名トークンからなる認識されないトリガー規則を使用すると、 ユーザーエージェントは警告を発するべきです。
実装は、ここで規定されていないトリガー規則をサポートできます。 ただし、その規則は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およびループ本体。 |
loop、while、またはforループのループ本体の開始中括弧('{')の直前。
| そのループ本体。 |
| 先頭となるcontinuing_compound_statement。 | そのcontinuing_compound_statement。 |
注: 次のものも複合文です。 関数本体、case節、単独のdefault 節、 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内にあり、かつ
-
LがAR'内にある別のフィルターDF'(AR',NS',TR)が存在する場合、 ARがAR'に含まれる。
影響範囲は入れ子になるため、最も近い外側の診断フィルターは次のいずれかになります。
-
一意の範囲診断フィルター、
-
そうでなければ、重複する(競合しない)グローバル診断 フィルターの集合の1つ、
-
そうでなければ、存在しません。
2.4. 制限
WGSL 実装は、次の制限を満たすシェーダーをサポートします。 WGSL 実装は、規定された制限を超えるシェーダーをサポートしてもかまいません。
注: WGSL 実装は、規定された制限を 超えるシェーダーをサポートしない場合、エラーを発するべきです。
| 制限 | サポートされる最小値 |
|---|---|
| 構造体型のメンバーの最大数 | 1023 |
| 複合型の最大入れ子の深さ | 15 |
| 関数内で中括弧に囲まれた文の最大入れ子深さ | 127 |
| 関数のパラメーターの最大数 | 255 |
| switch文内のcaseセレクター値の最大数。 各case文について、case値の数を合計します。 これにはdefault 節が含まれます。 | 1023 |
| 単一のシェーダーから静的にアクセスされる、 privateアドレス空間でインスタンス化された すべての変数の バイトサイズの最大合計 | 8192 |
| 単一の関数内で宣言され、 functionアドレス空間で インスタンス化されたすべての変数の バイトサイズの最大合計 | 8192 |
|
単一のシェーダーから静的にアクセスされる、
workgroupアドレス空間で
インスタンス化されたすべての変数の
バイトサイズの最大合計
この制限の目的上、 固定フットプリント配列は、オーバーライド値を代入するとき、 作成時固定フットプリント配列として扱われます。 これは WebGPU のmaxComputeWorkgroupStorageSize 制限を 単独の WGSL 制限に対応付けます。 | 16384 |
|
即時データ
変数の
最大バイトサイズ。
これは WebGPU のmaxImmediateSize制限を 単独の WGSL 制限に対応付けます。 | 64 |
| 配列型の値 コンストラクター式に含まれる要素の最大数 | 2047 |
3. テキスト構造
text/wgslメディアタイプは、コンテンツを WGSL モジュールとして識別するために使用されます。
付録A:text/wgsl メディアタイプを参照してください。
WGSL モジュールは、バイトオーダーマーク(BOM)のない、UTF-8 エンコーディングを使用した Unicode テキストです。
WGSL モジュールのテキストは、一連の Unicode コードポイントからなり、次のものを形成する連続した空でない集合にまとめられます。
プログラムテキストには、ヌルコードポイント(U+0000)を含めてはなりません。
3.1. 構文解析
WGSL モジュールを構文解析するには、次のようにします。
コメントを削除します。
最初のコメントを空白コードポイント(
U+0020)に置き換えます。コメントがなくなるまで繰り返します。
§ 3.9 テンプレートリストのアルゴリズムを使用して、テンプレートリストを検出します。 この手順により、
'<'(U+003C)および'>'(U+003E)コード ポイントを、テンプレートリストの区切り文字として使用する場合と、比較演算子などのその他の用途に使用する場合との 曖昧さが解消されます。translation_unit 文法規則への一致を試みながら、テキスト全体を構文解析します。 構文解析には、次のカスタマイズを施した LALR(1) パーサー(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 6.1節「調整不可能な行分割規則」のLB4およびLB5で定義される「強制分割」を示す空白として定義されます。 すなわち、改行は次のいずれかです。
-
改行(
U+000A) -
垂直タブ(
U+000B) -
改ページ(
U+000C) -
後ろに改行(
U+000A)が続かない復帰(U+000D) -
後ろに改行(
U+000A)が続く復帰(U+000D) -
次行(
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接尾辞。
注: 0ではない整数リテラルの先頭に0を付けること(例: 012)は禁止されています。 これは、先頭の0が8進数を意味する他の言語の表記との混同を避けるためです。
/0[iu]?/
| /[1-9][0-9]*[iu]?/
/0[xX][0-9a-fA-F]+[iu]?/
浮動小数点 リテラルは、10進浮動小数点リテラル または16進浮動小数点リテラルです。
浮動小数点 リテラルには、分数を表す仮数部と、省略可能な指数部という2つの論理的な部分があります。 おおまかには、リテラルの値は、底の値を指定された指数で累乗した値に仮数部を掛けたものです。 仮数部の数字が有効であるとは、その数字が0でないか、 または、その左側と右側の両方に0でない仮数部の数字があることをいいます。 有効数字は左から右へ数えます。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です。
-
それ以外の場合、次のようにします。
-
truncated_significandを、20番目の有効数字より 右側にある各数字を0に置き換えた点を除いて、 significandと同じものとします。
-
truncated_significand_nextを、次の点を除いてsignificandと 同じものとします。
-
20番目の有効数字を1増やし、各数字が0から9の範囲に収まるよう、 必要に応じて左側へ 桁上がりを伝播させます。
-
20番目の有効数字より右側にある各数字を0に置き換えます。
-
-
effective_significandをtruncated_significand またはtruncated_significand_nextのいずれかに設定します。 これは実装上の選択です。
-
-
-
リテラルの数学的な値は、 10進数の分数としてのeffective_significandの数学的な値に、 10の指数乗を掛けたものです。 指数が指定されていない場合、指数は0であるとみなされます。
注: 10進数の仮数部は20個の 10進数字の後で切り捨てられ、分数内にはおよそ log(10)/log(2)×20 ≈ 66.4 有効ビットが保持されます。
16進浮動小数点リテラルは、次のとおりです。
-
0xまたは0X接頭辞 -
その後に、16進数字の列として指定され、その途中に省略可能な16進小数点 (
.)を持つ仮数部。 仮数部は、16を底とする表記で分数を表します。 -
その後に、次のものからなる省略可能な指数接尾辞。
-
pまたはP -
その後に、省略可能な先行符号(
+または-)を持つ10進数として指定された指数。 -
その後に、省略可能な
fまたはh接尾辞。
-
-
16進小数点または指数のうち、少なくとも1つが存在しなければなりません。 いずれも存在しない場合、そのトークンは代わりに整数リテラルになります。
/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です。
-
それ以外の場合、次のようにします。
-
truncated_significandを、16番目の有効数字より 右側にある各数字を0に置き換えた点を除いて、 significandと同じものとします。
-
truncated_significand_nextを、次の点を除いてsignificandと 同じものとします。
-
16番目の有効数字を1増やし、各数字が0から
fの範囲に収まるよう、 必要に応じて左側へ 桁上がりを伝播させます。 -
16番目の有効数字より右側にある各数字を0に置き換えます。
-
-
effective_significandをtruncated_significand またはtruncated_significand_nextのいずれかに設定します。 これは実装上の選択です。
-
-
-
リテラルの数学的な値は、 16進数の分数としてのeffective_significandの数学的な値に、 2の指数乗を掛けたものです。 指数が指定されていない場合、指数は0であるとみなされます。
注: 16進数の仮数部は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接尾辞を持つ整数リテラルを 対象の型で表現できない場合。 -
fまたはh接尾辞を持つ16進浮動小数点リテラルが オーバーフローするか、対象の型で正確に表現できない場合。 -
fまたはh接尾辞を持つ10進浮動小数点リテラルが 対象の型でオーバーフローする場合。
注: 16進浮動小数点値 0x1.00000001p0 を 正確に表現するには仮数部に33ビット必要ですが、 f32には明示的な仮数部ビットが23ビットしかありません。
注: f接尾辞を使用して
16進浮動小数点リテラルをその型に強制する場合、そのリテラルでは
2進指数も使用する必要があります。たとえば、0x1p0fと記述します。これに対し、0x1fは
16進整数リテラルです。
3.6. キーワード
キーワードとは、 事前定義された言語概念を指すトークンです。 WGSL キーワードの一覧については、§ 16.1 キーワード一覧を参照してください。
3.7. 識別子
識別子とは、 名前として使用されるトークンの一種です。 § 5 宣言とスコープを参照してください。
WGSL では、用途を分けるために2つの文法非終端記号を使用します。
-
identは、 宣言されたオブジェクトの名前に使用されます。
-
member_identは、構造体型のメンバーの名前に使用されます。
識別子の形式は、 Unicode 標準附属書#31の Unicode バージョン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 バージョン14.0.0の Unicode 文字データベースには、 XID_Startおよび XID_Continueの両方について、 有効なすべてのコードポイントを含む参考情報の一覧が収録されています。
注: 一部の組み込み関数の戻り値の型は、その名前を
WGSL ソース内で使用できない構造体型です。
それらの構造体型は、2つのアンダースコアで始まる名前で事前宣言されているかのように記述されます。
結果値は、型推論を使用して新しく宣言されたletまたはvarへ
保存するか、そのメンバーの1つを名前によって
直ちに抽出できます。使用例については、frexpおよび
modfの説明を参照してください。
3.7.1. 識別子の比較
2つの WGSL 識別子は、同じコードポイント列からなる場合に限り同じです。
注: この仕様では、比較を目的とした値の Unicode 正規化は許可されません。 視覚的および意味的には同一でも、異なる Unicode 文字列を使用する値は一致しません。 コンテンツの作成者には、同じエンコーディング列を一貫して使用するか、値を選択するときに問題となる可能性のある 文字を避けることを推奨します。詳細については、[CHARMOD-NORM]を参照してください。
注: WGSL モジュールに現れる識別子をすべて、 その識別子の同形表記の1つに置き換えると意味が変わる場合、ユーザーエージェントは開発者に見える 警告を発するべきです。 (同形文字とは、読者には別のコードポイント列と同じに見える可能性があるコードポイント列です。 同形文字を検出するための対応付けの例としては、 前の段落で述べた変換、対応付け、および照合アルゴリズムがあります。ある識別子について、部分列をその同形文字に 繰り返し置き換えることで一方のコードポイント列をもう一方へ変換できる場合、その2つのコードポイント列は同形表記です。)
3.8. 文脈依存名
文脈依存 名とは、特定の文法的文脈においてのみ概念の名前として使用されるトークンです。 トークンの綴りは識別子と同じ場合がありますが、そのトークンは宣言されたオブジェクトへ解決されません。 この節では、文脈依存名として使用されるトークンを列挙します。 トークンはキーワードまたは予約語であってはなりません。
3.8.1. 属性名
§ 12 属性を参照してください。
attributeの名前は、 次のとおりです。
3.8.2. 組み込み値名
組み込み値 名トークンとは、組み込み値の名前で使用されるトークンです。
§ 13.3.1.1 組み込み入力と出力を参照してください。
組み込み値の名前は 次のとおりです。
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に対する補間型の名前で使用されるトークンです。
§ 13.3.1.4 補間を参照してください。
補間 型の名前は、次のとおりです。
3.8.7. 補間サンプリング名
補間サンプリング名トークンとは、 補間サンプリングの名前で使用されるトークンです。
§ 13.3.1.4 補間を参照してください。
補間 サンプリングの名前は、次のとおりです。
3.8.8. スウィズル名
スウィズル名は、 ベクトルアクセス式およびスウィズルビュー 式で使用されます。
/[rgba]/
| /[rgba][rgba]/
| /[rgba][rgba][rgba]/
| /[rgba][rgba][rgba][rgba]/
| /[xyzw]/
| /[xyzw][xyzw]/
| /[xyzw][xyzw][xyzw]/
| /[xyzw][xyzw][xyzw][xyzw]/
3.8.9. 深度モード名
深度モード 名トークンは、トークンであり、 frag_depth組み込み値で、fragment_depth機能が サポートされる場合に使用されます。
3.9. テンプレートリスト
テンプレート パラメーター化とは、一般的な概念を変更するパラメーターを指定する方法です。 テンプレートパラメーター化を記述するには、一般的な概念に続けてテンプレートリストを記述します。
コメントおよび空白を無視すると、テンプレートリストは次のとおりです。
-
先頭の
'<'(U+003C)コードポイント、その後に -
コンマで区切られた、 1つ以上のテンプレートパラメーターのリスト、その後に
-
省略可能な末尾のコンマ、その後に
-
終端の
'>'(U+003E)コードポイント。
テンプレート パラメーターの形式は、以下のテンプレートリスト検出アルゴリズムによって暗黙的に定義されます。 一般に、これらは名前、式、または型です。
注: たとえば、vec3<f32>という句は、
vec3が変更される一般的な概念であり、
<f32>が1つのパラメーターである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)コードポイントが現れるのは、比較演算の一部である場合のみです。 すなわち、'<='、'>='、'=='、または'!='の いずれかです。 それ以外の場合、'='(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をそれらの後まで進めます。
CurrentPositionに
'<'(U+003C)が現れる場合、次のようにします。
注: このコード ポイントは、テンプレートリストの先頭である候補です。 後で入力に現れる終端の
'>'(U+003E)と照合できるように、十分な状態を保存します。UnclosedCandidate(position=CurrentPosition,depth=NestingDepth)を Pendingスタックにプッシュします。
CurrentPositionを次のコードポイントへ進めます。
CurrentPositionに
'<'(U+003C)が現れる 場合、次のようにします。
注: 仮定1より、テンプレートパラメーターは
'<'(U+003C)で始まらないため、 直前のコードポイントをテンプレートリストの先頭とすることはできません。 したがって、現在と直前のコードポイントは'<<'演算子でなければなりません。Pendingスタックから最上位の項目をポップします。
CurrentPositionをこのコードポイントの後まで進め、 ループの次の反復を開始します。
CurrentPositionに
'='(U+003D)が現れる場合、次のようにします。
注: 仮定1より、テンプレートパラメーターは
'='(U+003C)で始まらないため、直前のコードポイントを テンプレートリストの先頭とすることはできません。 現在と直前のコードポイントが'<='比較演算子を形成すると仮定します。 後の手順で'='(U+003D)コードポイントを代入と誤認しないように、 そのコードポイントを読み飛ばします。Pendingスタックから最上位の項目をポップします。
CurrentPositionをこのコードポイントの後まで進め、 ループの次の反復を開始します。
ループの次の反復を開始します。
CurrentPositionに
'>'(U+003E)が現れる場合、次のようにします。
注: このコードポイントは、 テンプレートリストの末尾である候補です。
Pendingが空でない場合、その最上位の項目をTとし、 T.depthがNestingDepthと等しい場合、次のようにします。
注: このコード ポイントは、先頭がTに記録されている現在のテンプレートリストを終了します。
TemplateList(start_position=T.position, end_position=CurrentPosition)を DiscoveredTemplateListsに追加します。
PendingスタックからTをポップします。
CurrentPositionをこのコードポイントの後まで進め、 ループの次の反復を開始します。
それ以外の場合、このコードポイントはテンプレートリストを終了しません。
CurrentPositionをこのコードポイントの後まで進めます。
CurrentPositionに
'='(U+003D)が現れる場合、次のようにします。
注: 現在と直前のコードポイントが
'>='比較演算子を形成すると仮定します。 後の手順で'='(U+003D)コードポイントを代入と誤認しないように、 そのコードポイントを読み飛ばします。CurrentPositionをこのコードポイントの後まで進めます。
ループの次の反復を開始します。
CurrentPositionに
'('(U+0028)または'['(U+005B)が現れる 場合、次のようにします。
注: 入れ子の 式に入ります。
NestingDepthに1を加えます。
CurrentPositionをこのコードポイントの後まで進め、 ループの次の反復を開始します。
CurrentPositionに
')'(U+0029)または']'(U+005D)が現れる 場合、次のようにします。
注: 入れ子の 式から出ます。
Pendingスタックが空になるか、その最上位の項目の depthがNestingDepthより小さくなるまで、項目をポップします。
NestingDepthを0またはNestingDepth − 1の いずれか大きい方に設定します。
CurrentPositionをこのコードポイントの後まで進め、 ループの次の反復を開始します。
CurrentPositionに
'!'(U+0021)が現れる場合、次のようにします。
CurrentPositionをこのコードポイントの後まで進めます。
CurrentPositionに
'='(U+003D)が現れる場合、次のようにします。
注: 現在と直前のコードポイントが
'!='比較 演算子を形成すると仮定します。 後の手順で'='(U+003D)コードポイントを 代入と誤認しないように、そのコードポイントを読み飛ばします。CurrentPositionをこのコードポイントの後まで進めます。
ループの次の反復を開始します。
CurrentPositionに
'='(U+003D)が現れる場合、次のようにします。
CurrentPositionをこのコードポイントの後まで進めます。
CurrentPositionに
'='(U+003D)が現れる場合、次のようにします。
注: 現在と直前のコードポイントが
'=='比較演算子を形成すると仮定します。 後の手順で'='(U+003D)コードポイントを 代入と誤認しないように、そのコードポイントを読み飛ばします。CurrentPositionをこのコードポイントの後まで進め、 ループの次の反復を開始します。
注: このコードポイントは、 式の一部としては現れ得ず、したがってテンプレートリスト内にも現れ得ない代入の 一部であると仮定します。 保留中の閉じられていない候補を消去します。
NestingDepthを0に設定します。
Pendingスタックからすべての項目を削除します。
CurrentPositionをこのコードポイントの後まで進め、 ループの次の反復を開始します。
CurrentPositionに
';'(U+003B)、'{'(U+007B)、または':'(U+003A)が現れる場合、次のようにします。
注: これらは 式の途中には現れ得ず、したがってテンプレートリスト内にも現れ得ません。 保留中の閉じられていない候補を消去します。
NestingDepthを0に設定します。
Pendingスタックからすべての項目を削除します。
CurrentPositionをこのコードポイントの後まで進め、 ループの次の反復を開始します。
'&&'または'||'が CurrentPositionのテキストと一致する場合、次のようにします。
注: これらは 比較よりも優先順位が低い演算子です。現在の式レベルにある保留中の閉じられていない 候補をすべて棄却します。
注: この規則により、 プログラム断片
a<b || c>dではテンプレートリストは検出されません。 代わりに、2つの比較を短絡評価する論理和として認識されます。Pendingスタックが空になるか、その最上位の項目の depthがNestingDepthより小さくなるまで、項目をポップします。
CurrentPositionを2つのコードポイントの後まで進め、 ループの次の反復を開始します。
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に設定します。
-
-
現在のコードポイントの後まで進める直前に、ループの末尾へ次の検査を挿入します。
-
CurrentPositionに「
,」(U+002C)が現れ、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)コードポイントで終わる1つのテンプレートリストがあり、そのテンプレート引数は
B>=Cです。
最初の'>'(U+003C)コードポイント(Bの後)を検査した後、
'='(U+003D)コードポイントが代入の一部とみなされないよう、特別に認識する必要があります。
注:
A<(B!=C)>という句を検査するとき、最初の'<'(U+003C)
コードポイントから始まり、最後の'>'(U+003E)コードポイントで終わる1つのテンプレートリストがあり、そのテンプレート引数は
B!=Cです。
'!'(U+0021)コードポイント('B'の後)を検査した後、
'='(U+003D)コードポイントが代入の一部とみなされないよう、特別に認識する必要があります。
注:
A<(B==C)>という句を検査するとき、最初の'<'(U+003C)
コードポイントから始まり、最後の'>'(U+003E)コードポイントで終わる1つのテンプレートリストがあり、そのテンプレート引数は
B==Cです。
最初の'='(U+003D)コードポイント('B'の後)を検査した後、
どちらも代入の一部とみなされないよう、2つ目の
'='(U+003D)コードポイントを特別に認識する必要があります。
テンプレート リストの検出が完了した後、 構文解析は、各テンプレートリストをtemplate_list 文法規則に一致させることを試みます。
_template_args_start template_arg_comma_list _template_args_end
template_arg_expression ( ',' template_arg_expression ) * ',' ?
4. 指令
指令は、 WebGPU 実装が WGSL プログラムを処理する方法を変更するトークン列です。
指令は省略可能です。 指令が存在する場合、すべての指令は、あらゆる宣言またはconst アサーションより前に現れなければなりません。
4.1. 拡張
WGSL は、時間の経過とともに進化することが想定されています。
拡張は、 WGSL 仕様に対する一貫した変更の集合を名前付きでまとめたものであり、次のものを任意に組み合わせて構成されます。
-
新しい構文による新しい概念および動作の追加。これには次のものが含まれます。
-
宣言、文、属性、および組み込み関数。
-
-
現在の仕様または以前に公開された拡張にある制限の撤廃。
-
許容される動作の集合を狭めるための構文。
-
プログラムの一部で利用できる機能を制限するための構文。
-
拡張が既存の仕様、および必要に応じて他の拡張とどのように相互作用するかについての説明。
仮に、拡張では次のことが可能です。
-
異なるビット幅の整数など、数値スカラー型を追加する。
-
浮動小数点の丸めモードを制約する構文を追加する。
-
シェーダーがアトミック型を使用しないことを示す構文を追加する。
-
新しい種類の文を追加する。
-
新しい組み込み関数を追加する。
-
シェーダー呼び出しの実行方法を制約する構文を追加する。
-
新しいシェーダーステージを追加する。
4.1.1. 有効化拡張
有効化拡張は、 次の条件を満たす場合にのみ機能を利用できる拡張です。
-
実装がその拡張をサポートしており、かつ
-
シェーダーがenable指令によって明示的にその拡張を要求し、かつ
-
対応する WebGPU の
GPUFeatureNameが、GPUDeviceの作成時に要求された必須機能の1つである。
有効化拡張は、 普遍的にはサポートされていないハードウェア機能を公開することを目的としています。
enable指令は、 1つ以上の有効化拡張のサポートを有効にする指令です。 実装が列挙されたすべての有効化拡張をサポートしていない場合、シェーダー作成 エラーになります。
'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" | WGSL モジュール内で、サブグループ組み込み値、 サブグループ組み込み関数、および クアッド組み込み関数を使用できます。 それ以外の場合、いずれを使用してもシェーダー作成エラーになります。 |
primitive_index
| "primitive-index"
| 組み込み変数primitive_indexを WGSL モジュール内で使用できます。それ以外の場合、primitive_indexを使用すると、 シェーダー作成エラーになります。 |
subgroup_size_control
| "subgroup-size-control"
| 属性subgroup_sizeを WGSL モジュール内で使用できます。
それ以外の場合、subgroup_sizeを使用すると、シェーダー作成エラーになります。
subgroup_size_controlが有効になると、subgroupsが自動的に有効になります。
|
// 任意精度浮動小数点型のための仮想的な拡張を有効にする。 enable arbitrary_precision_float ; enable arbitrary_precision_float ; // 冗長な enable 指令も許容される。 // 丸めモードを制御するための仮想的な拡張を有効にする。 enable rounding_mode ; // arbitrary_precision_float により次の使用が有効になると仮定する。 // - 型 f<E,M> // - 関数の戻り値、仮パラメーター、および let 宣言における型としての使用 // - AbstractFloat からの値コンストラクターとしての使用 // - 除算演算子 / のオペランド // @rounding_mode 属性は、rounding_mode enable 指令によって有効になると仮定する。 @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ループは言語 拡張になり得ます。
WebGPU のGPU
オブジェクトのwgslLanguageFeatures
メンバーは、実装がサポートする
言語拡張の集合を列挙します。
requires指令は、 プログラムが1つ以上の言語拡張を使用することを文書化する指令です。 実装が公開する機能は変更しません。 実装が必須拡張のいずれかをサポートしていない場合、シェーダー作成 エラーになります。
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アクセスモードを ストレージテクスチャで使用できるようにします。 さらに、textureBarrier組み込み関数を追加します。 |
| packed_4x8_integer_dot_product | 8ビット整数の4成分ベクトルをパックした32ビット整数スカラーを、 dot4U8Packedおよび dot4I8Packed組み込み関数による内積命令の入力として使用できるようにします。 さらに、8ビット整数のパックされた4成分ベクトルを使用するパックおよびアンパック命令を、 pack4xI8、pack4xU8、 pack4xI8Clamp、pack4xU8Clamp、 unpack4xI8、およびunpack4xU8 組み込み関数によって追加します。 |
| unrestricted_pointer_parameters | ユーザー定義関数から、次の制限を撤廃します。 |
| pointer_composite_access |
ルート式がポインターであり、参照を生成する複合値
分解式をサポートします。
たとえば、 同様に、 |
| uniform_buffer_standard_layout | uniformアドレス空間内のバッファが、 他のアドレス空間と同じメモリレイアウト制約を使用できるようにします。 |
| subgroup_id | subgroups 拡張が有効である場合に、subgroup_idおよびnum_subgroups組み込み値を使用できるようにします。 |
| subgroup_uniformity |
サブグループおよび
クアッド組み込み関数に対する一様な制御フローに、
同じサブグループ内のすべての呼び出しからなる
サブグループという追加のスコープを加えます。
注: サブグループおよびクアッド 組み込み関数を使用するには、 subgroups拡張を有効にする必要があります。 |
| texture_and_sampler_let | let宣言の実効値型を、 テクスチャ型またはサンプラー型にできるようにします。 |
| texture_formats_tier1 | 次の追加のテクセル 形式をサポートします。 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 を介してコマンドエンコーダーから直接渡される、
頻繁に更新される少量のデータにバインドできるようにします。
|
| fragment_depth |
frag-depth組み込み値に対して、
モードlessおよびgreaterを持つ
新しいdepth_mode組み込みパラメーターを導入します。
これらは、フラグメントシェーダーが、既存の深度より小さい(または大きい)ことが
保証される深度値だけを書き込むと宣言するときに使用されます。
|
| buffer_view |
バッファ型および
buffer_view組み込み関数を使用できるようにします。
他のホスト共有可能型として再解釈できる、 不透明な格納型を持つ変数の宣言を許可します。 |
| swizzle_assignment |
スウィズルビュー型を
サポートします。
これにより、スウィズル代入が可能になります。 単一の代入文で、ベクトル全体を更新することなく ベクトルの複数の成分を更新できます。 たとえば、変数 pointer_composite_access
もサポートされている場合、
これはポインターでも機能します。 |
注: その時点で一般的にサポートされている 言語拡張のすべての機能を具体化する言語拡張を、WGSL が時間の経過とともに定義していくことを意図しています。 requires指令では、これらは一般的な機能をすべて列挙するための 簡略形式として機能します。 これらは段階的に増大する機能の集合を表しており、ある種の言語バージョンと考えることができます。
4.2. グローバル診断フィルター
グローバル診断
フィルターは、その影響範囲が
WGSL モジュール全体である診断フィルターです。
これは指令であるため、
あらゆるモジュールスコープ
宣言より前に現れます。
属性形式と同じように表記されますが、先頭の@(U+0040)コードポイントはなく、
末尾にセミコロンが付きます。
'diagnostic' diagnostic_control ';'
5. 宣言とスコープ
宣言は、 識別子を次のいずれかの種類のオブジェクトに関連付けます。
言い換えると、宣言はオブジェクトの名前を導入します。
宣言がプログラムのソース内に現れるものの、 他のいかなる宣言のテキスト内にも現れない場合、その宣言はモジュール スコープにあります。
関数宣言は モジュールスコープに現れます。 関数宣言は、仮パラメーターがある場合、その宣言を含み、 また、その本体内に変数および値の宣言を含む場合があります。 したがって、これらの内包された宣言はモジュールスコープにはありません。
注: 別の宣言を含む唯一の種類の宣言は、 関数宣言です。
特定のオブジェクトは 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つの非モジュールスコープ宣言についてスコープ内にある場合、 そのトークンは、それらの宣言のうち最も近い宣言に関連付けられたオブジェクトを表します。
注: そのような最も近い宣言は、 識別子トークンより前に現れます。
-
それ以外の場合、その名前を持つモジュールスコープ宣言が存在するなら、トークンは その宣言されたオブジェクトを表します。
注: モジュールスコープ宣言は、 識別子トークンの前または後に現れる場合があります。
-
それ以外の場合、その名前を持つ事前宣言済みのオブジェクトが存在するなら、トークンはその オブジェクトを表します。
上記のアルゴリズムを使用して識別子を宣言に対応付ける場合、その識別子が その宣言へ解決されるといいます。 同様に、その識別子が宣言されたオブジェクトへ解決されるともいいます。
いずれかのモジュールスコープ宣言が再帰的である場合、 シェーダー作成エラーになります。 すなわち、宣言間に循環が存在してはなりません。
次のような有向グラフを考えます。
各ノードは宣言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.5.3 参照型およびポインター型を参照してください。
注: スウィズルビュー型は WGSL モジュール内には記述されません。§ 6.5.4 スウィズルビュー型を参照してください。
6.1. 型検査
WGSL の値は、式を評価することによって計算されます。
式は、
名前が「expression」で終わる WGSL 文法規則の1つとして構文解析される
ソーステキストの区間です。
式Eには、外側の式Eに完全に含まれる式である部分式を含めることができます。
最上位
式は、それ自体が部分式ではない式です。
§ 8.19 式文法の概要を参照してください。
式の評価によって生成される特定の値は、次のものに依存します。
-
静的文脈: 式を囲むソーステキスト、および
-
動的 文脈: 式を評価する呼び出しの状態、 およびその呼び出しが実行されている実行文脈。
特定の式を評価した結果となり得る値は、常に特定の WGSL 型に属します。 この型を、式の静的型と呼びます。 WGSL の規則は、式の静的型が、その式の静的 文脈のみに依存するよう設計されています。
型表明は、 ある WGSL ソース式から WGSL 型への対応付けです。 次の表記
e : T
は、Tが WGSL 式eの静的型であることを意味する型表明です。
注: 型表明は、 プログラムのテキストに関する事実の記述です。 実行時検査ではありません。
文では式が頻繁に使用され、その式の静的型に要件が課される場合があります。 次に例を示します。
正常に構文解析された WGSL モジュールの型検査とは、 各式をその静的型に対応付け、 各文の型要件が満たされていることを検証する処理です。 型検査が失敗した場合、型エラーと呼ばれる、シェーダー作成エラーの特殊な場合になります。
型検査は、構文的な句に型規則を再帰的に適用することで実行できます。 ここで、構文的な句は、式または文のいずれかです。 型規則は、 構文的な句の静的文脈によって、 その句に含まれる式の静的型がどのように決定されるかを説明します。 型規則には、次の2つの部分があります。
-
結論。
-
前提条件。次のものからなります。
型規則は、その前提条件および結論に型パラメーターを持つ場合があります。 型規則の結論または前提条件に型パラメーターが含まれている場合、その型規則をパラメーター化済みと呼びます。 型パラメーターが含まれていない場合、その規則を完全に具体化済みと呼びます。 パラメーター化された型規則の各型パラメーターを型で置換することにより、 完全に具体化された型規則を作成できます。 このとき、規則内にある同じパラメーターのすべての出現箇所には、同じ型を使用します。 規則の型パラメーターに型を割り当てることを、置換と呼びます。
たとえば、次に論理否定
(!e形式の式)の型規則を示します。
| 前提条件 | 結論 |
|---|---|
| e: T TはboolまたはvecN<bool> | !e: T
|
これは型パラメーターTを含むため、パラメーター化された規則です。
Tは、
bool、vec2<bool>、
vec3<bool>、またはvec4<bool>という4つの型のいずれかを表せます。
Tをvec3<bool>へ対応付ける置換を適用すると、
次の完全に具体化された型規則が生成されます。
| 前提条件 | 結論 |
|---|---|
e: vec3<bool> | !e: vec3<bool>
|
規則の他の条件を満たす何らかの置換を適用することによって、 パラメーター化された規則から生成できる完全に具体化された各規則を、 そのパラメーター化された規則のオーバーロードと呼びます。 たとえば、真偽値否定規則には4つのオーバーロードがあります。 これは、その型パラメーターTへ型を割り当てる方法が4通りあるためです。
注: 言い換えると、パラメーター化された型規則は、 完全に具体化された型規則の集合に対するパターンを提供します。 各規則は、パラメーター化された規則に異なる置換を適用することで生成されます。
次の場合、型規則が構文的な句に適用されます。
-
規則の結論が、構文的な句の有効な構文解析に一致し、かつ
-
規則の前提条件が満たされる。
パラメーター化された型規則は、 式に適用される完全に 具体化された型規則を生成する置換が存在する場合、 その式に適用されます。
式1u+2uについて考えます。
この式には、1uおよび2uという2つのリテラル部分式があり、
どちらもu32型です。
最上位
式は加算です。
§ 8.8 算術式の規則を参照すると、次の理由により、加算の型規則が
この式に適用されます。
-
1u+2uはe1+e2形式の構文解析に一致し、e1は1uを、e2は2uを表し、かつ -
e1はu32型であり、かつ
-
e2はu32型であり、かつ
-
型規則の型パラメーターTをu32で置換でき、その結果、 式全体に適用される完全に具体化された規則が得られる。
構文的な 句を解析するとき、次の3つの場合があります。
-
式に適用される型規則がない場合。これは型エラーになります。
-
正確に1つの完全に 具体化された型規則が式に適用される場合。 この場合、その規則の結論が表明され、式の静的型が決定されます。
-
複数の型規則が適用される場合。すなわち、複数のオーバーロードの前提条件が満たされる場合。 この場合、§ 6.1.3 オーバーロード解決で説明する優先順位決定手順が使用されます。
上記の例を続けると、式1u+2uには1つの型規則だけが適用されるため、
型検査は、その型規則の結論、すなわち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 | メモリ参照から値をロードするために、ロード規則を適用します。 |
| swizzle<AS,S,N,K> | vecK<S> | 0 | スウィズルビューのロード規則を適用して、 スウィズルビューからベクトル値をロードします。 |
| AbstractFloat | f32 | 1 | § 15.7.6 浮動小数点変換を参照 |
| AbstractFloat | f16 | 2 | § 15.7.6 浮動小数点変換を参照 |
| AbstractInt | i32 | 3 | 値が i32 で表現可能なら恒等変換。 それ以外の場合はシェーダー作成エラーになります。 |
| AbstractInt | u32 | 4 | 値が u32 で表現可能なら恒等変換。 それ以外の場合はシェーダー作成エラーになります。 |
| 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 | |
| ptr<AS, buffer<N1>, AM> ここで Src は関数呼び出しの引数の型です | ptr<AS, buffer<N2>, AM> ここで N1 と N2 はどちらも定数式であり、Dest は Src の引数に対応する仮パラメーターの型です | N2 < N1 の場合は 1、 それ以外は無限大 | 固定サイズバッファのポインター引数を、より小さいサイズの ポインターパラメーターへ変換します。1 |
| ptr<AS, buffer<N>, AM> ここで Src は関数呼び出しの引数の型です | ptr<AS, buffer, AM> ここで Dest は Src の引数に対応する仮パラメーターの型です | 1 | 固定サイズバッファのポインター引数を実行時サイズバッファのポインターパラメーターへ変換します。1 |
| S | T 上記のケースが適用されない場合 | 無限大 | その他の型の間には自動変換がありません。 |
-
これらの変換には、unrestricted_pointer_parameters および buffer_view 言語機能が必要です。
次の場合、型 T は型 S の具象化です:
-
Tが具象であり、かつ -
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 のオーバーロード解決は、単一の最も優先されるオーバーロード 候補を見つけることを目的として、次のように進行します:
-
各候補 C について、構文句内の部分式の変換ランクを列挙します。 候補の前提条件は満たされているため、P 内の i 番目の部分式について:
-
その静的型は計算済みです。
-
式の静的型から、前提条件内の対応する型表明が要求する型への実行可能な自動変換があります。 C.R(i) を、その変換のConversionRank とします。
-
-
実行可能な自動変換後に、ある部分式が抽象型へ解決される一方、 候補内の別の部分式が定数式ではない候補を除外します。
注: その結果、構文句内のいずれかの部分式が定数式でない場合、 構文句内のすべての部分式は具象型を持たなければなりません。
-
候補をランク付けします:2つのオーバーロード候補 C1 と C2 が与えられたとき、次の場合に C1 は C2 より優先されます:
-
P 内の各式位置 i について、C1.R(i) ≤ C2.R(i)。
-
すなわち、C1 を P に適用するために必要な各式変換が、 C2 を P に適用するために必要な対応する式変換と同等以上に優先されます。
-
-
C1.R(i) < C2.R(i) となる式位置 i が少なくとも1つあります。
-
すなわち、C1 を適用するために必要な式変換のうち少なくとも1つが、 C2 を適用するために必要な対応する変換より厳密に優先されます。
-
-
-
他のすべての候補より優先される候補 C が1つだけある場合、 オーバーロード解決は成功し、候補の型規則 C が得られます。 それ以外の場合、オーバーロード解決は失敗します。
6.2. 単純型
単純型は、真偽値、数値、ベクトル、 行列、またはそのような値の集約を機械上で表現するための型です。
単純型は、スカラー型、アトミック型、 または複合型のいずれかです。
注: WGSL の単純型は C++ の Plain-Old-Data 型に似ていますが、 アトミック型と抽象数値型も含みます。
6.2.1. 抽象数値型
これらの型を WGSL ソース内に記述することはできません。これらは型検査でのみ使用されます。
特定の式はシェーダー作成時に、 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)。 -
1は f32 値1.0fに変換され(ランク 5)、2.5は f32 値2.5fに変換されます(ランク 1)。 -
1は f16 値1.0fに変換され(ランク 6)、2.5は f16 値2.5hに変換されます(ランク 2)。
-
-
最初のオーバーロードが優先される候補となり、型検査は成功します。
-
結果となる計算は AbstractFloat の
1.0 + 2.5として行われます。
例:let x = 1 + 2.5;
-
この例は上記と似ていますが、
xは抽象数値型へ解決できません。 -
この宣言の効果は、
let x : f32 = 1.0f + 2.5f;と記述した場合と同じです。
例:1u + 2.5 はシェーダー作成エラーになります:
-
1u項は u32 型の式です。 -
2.5項は AbstractFloat 型の式です。 -
有効なオーバーロード候補はありません:
例:-1 * i32(-2147483648) はシェーダー作成エラーになりません:
-
-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 // 接尾辞のない整数リテラルは、必要な場合に浮動小数点へ変換できる: // 変換ランク 5 で AbstractInt を f32 へ自動変換する。 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 を選択するが、値が // 範囲外であり、シェーダー作成エラーが発生する。 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 ); // 次の例はすべて f32 に昇格し、初期値は 10f となる。 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
| 真の値。 | |
false: bool
| 偽の値。 |
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ビット浮動小数点値の集合です。プログラムに
enable f16; ディレクティブが含まれ、f16 拡張が有効になっていない状態で
f16 型を使用すると、シェーダー作成
エラーになります。詳細については、§ 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> | 型 T の C 列 R 行の行列。ここで、C と R はどちらも {2, 3, 4} のいずれかであり、T は f32、f16、または AbstractFloat でなければなりません。 同等に、型 vecR<T> の C 個の列ベクトルとして 捉えることもできます。 |
行列の主な用途は、線形変換を表現することです。 この解釈では、行列のベクトルは列ベクトルとして扱われます。
積演算子(*)は、次のいずれかに使用されます:
-
スカラー量によって変換を拡大縮小する。
-
変換をベクトルに適用する。
-
変換を別の行列と合成する。
§ 8.8 算術式を参照してください。
| 事前宣言済みのエイリアス | 元の型 | 制限 |
|---|---|---|
| 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 アクセスモードを持つストレージ
バッファ変数によってのみインスタンス化できます。
この型に対する演算のメモリスコープは、それがインスタンス化されるアドレス空間によって決まります。
workgroup アドレス空間内のアトミック型は、
Workgroup のメモリスコープを持ちます。一方、
storage
アドレス空間内のものは、QueueFamily のメモリスコープを持ちます。
アトミック 変更とは、アトミックオブジェクトの内容を設定する、そのオブジェクトに対する任意の 演算です。 新しい値がオブジェクトの既存の値と同じであっても、その演算は変更として数えられます。
WGSL では、アトミック変更はオブジェクトごとに相互に順序付けられます。 すなわち、シェーダーステージの実行中、各アトミックオブジェクト A について、すべての エージェントは A に適用された変更演算を同じ順序で観察します。 異なるアトミックオブジェクトの順序付けには、いかなる関係もない場合があります。 因果関係は含意されません。 workgroup 空間内の変数は、 1つのワークグループ内では共有されますが、 異なるワークグループ間では共有されないことに注意してください。
6.2.9. 配列型
配列は、 インデックスでアクセス可能な要素値の列です。
| 型 | 説明 |
|---|---|
| array<E,N> | 型 E の要素を N 個持つ固定サイズ
配列。 N は配列の要素数と呼ばれます。 |
| array<E> | 型 E の要素からなる実行時サイズ配列。
これは特定の文脈でのみ使用できます。 |
配列の最初の要素のインデックスは 0 であり、後続の各要素は次の整数インデックスにあります。 § 8.5.3 配列アクセス式を参照してください。
式を評価した結果が実行時サイズ配列型になってはなりません。
固定サイズ配列の要素数式 N には、次の制約が適用されます:
-
評価結果が具象整数スカラーにならなければなりません。
-
N が0より大きくない場合:
-
N が定数式である場合、シェーダー作成エラーになります。
-
それ以外の場合、パイプライン作成エラーになります。
-
注: N がオーバーライド宣言に依存する場合、要素数の値はパイプライン作成時に完全に決定され、 それ以外の場合はシェーダーモジュール作成時に完全に決定されます。
注: 型の等価性を満たすには、定数式ではないオーバーライド式が 識別子でなければなりません。 オーバーライド可能な定数によってサイズが決まるワークグループ変数を参照してください
実行時サイズ配列の要素数は、対応するストレージバッファ変数に関連付けられた バッファバインディングのサイズによって決定されます。 § 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 アドレス空間内のメモリビューだけです。 これには、ワークグループ変数の格納型が含まれます。 § 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>; // オーバーライド可能な要素数はワークグループ変数に対してのみ // 有効であるため、無効な例。 // 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 はレイアウト属性であり、 構造体型を使用してuniform バッファまたはストレージバッファを定義する場合に必要となることがあります。 § 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) と記述する T の入れ子の深さは、次のとおりです:
-
ベクトル型の場合は 1
-
行列型の場合は 2
-
要素型が E である配列型の場合は 1 + NestDepth(E)
-
T がメンバー型 M1,...,MN を持つ構造体型である場合は、 1 + max(NestDepth(M1),..., NestDepth(MN))
6.2.12. 構築可能型
多くの種類の値は、作成、ロード、格納、関数への受け渡し、 および関数からの返却が可能です。 これらを構築可能と呼びます。
次のいずれかである場合、その型は構築可能です:
注: すべての構築可能型は作成時固定フットプリントを持ちます。
注: アトミック型と実行時サイズ配列型は構築可能ではありません。 アトミック型および実行時サイズ配列を含む複合型も構築可能ではありません。
6.2.13. 固定フットプリント型
変数のメモリフットプリントとは、 変数の内容を格納するために使用されるメモリ位置の数です。 変数のメモリフットプリントは、その格納型に依存し、 シェーダーのライフサイクルのいずれかの時点で確定します。 ほとんどの変数のサイズは、非常に早いシェーダー作成時に決定されます。 一部の変数のサイズは、より後のパイプライン作成時に決定され、 さらに別のものはシェーダー実行の開始時になって初めて決定される場合があります。
ある型の具象化のサイズが、 シェーダー作成時に完全に決定される場合、その型は 作成時固定フットプリントを持ちます。
ある型のサイズがパイプライン作成時に完全に決定される場合、 その型は固定 フットプリントを持ちます。
注: すべての具象の作成時固定フットプリント型および 固定フットプリント型は格納可能です。
注: パイプライン作成はシェーダー作成に依存するため、 作成時固定フットプリントを持つ型は、 固定フットプリントも持ちます。
作成時固定フットプリントを持つ型は、次のとおりです:
-
スカラー型
-
ベクトル型
-
行列型
-
次の場合の固定サイズ 配列型:
-
すべてのメンバーが作成時固定フットプリントを持つ構造体型。
-
次の場合の固定サイズ バッファ型:
-
そのサイズが定数式である。
-
注: 構築可能型は作成時固定フットプリントを持ちます。
固定 フットプリントを持つ型は、次のいずれかです:
-
作成時固定フットプリントを持つ型
-
固定サイズ バッファ型(そのサイズをさらに制限しない)
注: 要素数が定数式ではないオーバーライド式である固定サイズ配列の有効な用途は、 workgroup アドレス空間内の メモリビューだけです。 これには、ワークグループ変数の格納型が含まれます。
注: 固定フットプリント型は、直接または間接的に アトミック型を含むことができますが、 構築可能型は含むことができません。
注: 固定フットプリント型には、 実行時サイズ配列、 実行時サイズバッファ、および実行時サイズ配列を含むすべての構造体が含まれません。
6.3. バッファ型
これらの型には、buffer_view 言語機能が必要です。
バッファ値は、 その内容を別のホスト共有可能型として解釈できるメモリを表します。 それ以外の点では、バッファ値は不透明です。 変数内のデータへ複数の異なる型としてアクセスする必要がある場合や、 シェーダー作成者が1つの変数を複数の論理変数へ分割したい場合に役立ちます。
バッファ型は構築可能ではなく、 buffer_view 組み込み関数によって そのデータを不透明でないホスト共有可能型として解釈した後にのみアクセスできます。
| 型 | 説明 |
|---|---|
| buffer<N> | N バイトのストレージを持つ固定サイズ
バッファ。 N はオーバーライド式でなければなりません。 |
| buffer | 実行時サイズバッファ。 |
固定サイズバッファは、storage、uniform、および workgroup アドレス空間内の変数によってのみインスタンス化できます。 storage および uniform アドレス空間では、サイズは定数式でなければなりません。 実行時サイズバッファは、storage アドレス空間内の変数によってのみインスタンス化できます。
N が0より大きくない場合:
-
N が定数式である場合、シェーダー作成エラーになります。
-
それ以外の場合、パイプライン作成エラーになります。
f16 拡張が有効であり、 N が2で割り切れない場合:
-
N が定数式である場合、シェーダー作成エラーになります。
-
それ以外の場合、パイプライン作成エラーになります。
f16 拡張が有効ではなく、 N が4で割り切れない場合:
-
N が定数式である場合、シェーダー作成エラーになります。
-
それ以外の場合、パイプライン作成エラーになります。
次の条件のいずれかが成り立つ場合に限り、2つのバッファ型は同じです:
-
両方とも実行時サイズである。
-
両方とも作成時固定フットプリントを持つ固定サイズであり、 一方が符号付きで他方が符号なしであっても、サイズの値が等しい。 (サイズは常に正であるため、この場合は符号付き値と符号なし値を比較できます。)
-
両方とも固定サイズであり、サイズが、パイプラインでオーバーライド可能な定数の 同じ宣言へ解決される識別子として指定されている。
6.4. 列挙型
列挙型は、 名前を持つ有限の値の集合です。 列挙型は、有効なテクセル形式の集合など、特定の概念に対する選択肢の集合を区別するために使用されます。
列挙子は、 列挙型に含まれる名前付きの値の1つです。 各列挙子は、 他のすべての列挙子、および他のすべての種類の値とは異なります。
WGSL ソース内で新しい列挙子または新しい列挙型を宣言する仕組みはありません。
注: 列挙子はテンプレートパラメーターとして使用されます。
6.4.1. 事前宣言済みの列挙子
次の表は、WGSL の列挙型、その事前宣言済みの列挙子、および列挙型に必要な言語拡張を示します。 列挙型は存在しますが、WGSL ソース内に記述することはできません。
6.5. メモリビュー
WGSL プログラムは、単純値による計算に加えて、 メモリアクセス演算によって、 メモリから値を読み取ったり、メモリへ値を書き込んだりすることもよくあります。 各メモリアクセスは、メモリビューを介して実行されます。
メモリビューは、 次のものから構成されます:
メモリビューのアクセスモードは、アドレス空間によってサポートされていなければなりません。 § 7 変数および値の宣言を参照してください。
6.5.1. 格納可能型
変数に含まれる値は、 格納可能型でなければなりません。 格納可能型は、§ 14.4.4 値の内部レイアウトで説明するように、 WGSL によって定義された明示的な表現を持つ場合があります。また、 テクスチャやサンプラーのように不透明である場合もあります。
ある型が具象であり、かつ次のいずれかである場合、 その型は格納可能です:
注: すなわち、格納可能型とは、 具象単純型、 テクスチャ型、サンプラー型、およびバッファ型です。
6.5.2. ホスト共有可能型
ホスト共有可能型は、ホストと GPU の間で共有されるバッファ、 または形式変換を行わずにホストと GPU の間でコピーされるバッファの内容を記述するために使用されます。 この目的で使用する場合、§ 14.4 メモリレイアウトで説明するように、 その型へレイアウト属性を追加で適用できます。 § 7.3 var 宣言で説明するように、uniform バッファ変数およびストレージバッファ変数の格納型は、 ホスト共有可能でなければなりません。
ある型が具象であり、かつ次のいずれかである場合、 その型はホスト共有可能です:
-
行列型
-
作成時固定フットプリントを持ち、 その要素型がホスト共有可能である固定サイズ 配列型
-
その要素型がホスト共有可能である実行時サイズ配列型
-
すべてのメンバーがホスト共有可能である構造体型
-
バッファ型
注: ステージ間の入力および出力の型に対する制限は、 § 13.3.1 ステージ間の入力および出力インターフェイスおよび それ以降の節で説明します。 これらの型にもサイズがありますが、数え方は異なります。
注: テクスチャと サンプラーもホストと GPU の間で共有できますが、その内容は不透明です。 この節のホスト共有可能型は、特にstorage および uniform バッファで使用するためのものです。
6.5.3. 参照型とポインター型
WGSL には、メモリビューを表現するための2種類の型があります: 参照型とポインター型です。
| 制約 | 型 | 説明 |
|---|---|---|
| AS はアドレス空間、 T は格納可能型、 AM はアクセスモード | ref<AS,T,AM> |
参照
型は、
AS 内にあり、型 T の値を保持し、
モード AM によって記述されるメモリアクセスをサポートするメモリ位置の
メモリビューの集合と同一視されます。
ここで、T は格納型です。 参照型は WGSL ソース内には記述されず、 代わりに 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.5.4. スウィズルビュー型
スウィズルビューは、 メモリ内のベクトルの成分の一部へアクセスし、 読み取り時にはそれらを並べ替え、書き込み時にはそれらを分散させるために使用できます。
スウィズルビューは、swizzle_assignment 言語拡張によって有効になります。
-
p は、read_write アクセスモードを持つ、 型 vecN<S> のベクトルへのポインターです。
-
IndexList = « Idx0, ..., IdxK−1 » は、次の条件を満たすインデックスの列です:
-
各 Idxi は [0,N−1] の範囲内です。
-
vecK<S> は有効なベクトル型です。すなわち、K は {2,3,4} のいずれかです。
-
アルゴリズム: SwizzleViewRead
ポインター p を介して読み取ったベクトルの成分を選択し、 必要に応じて並べ替えて形成したベクトルを生成します。
注: スウィズルビューを介した読み取りでは、 一部のベクトル成分が結果に現れない場合でも、ベクトル全体をメモリから読み取ります。
入力:型 swizzle<AS,S,N,K> のスウィズル ビュー (p, IndexList)
出力:型 vecK<S> のベクトル値 v。 (p, IndexList) を読み取った結果です。
手順:
慣例により、IndexList = « Idx0, ..., IdxK−1 » とします
p が参照するメモリからベクトル u を読み取ります。 u の型は vecN<S> です。
次の条件を満たす、型 vecK<S> の値 v を形成します:
v の成分 i は、 u の成分 Idxi の値に等しくなります。 インデックス構文を使用すると: v[i] = u[Idxi]
アルゴリズム: SwizzleViewWrite
update ベクトルの成分を、ポインター p が参照する メモリ内のベクトルの指定された成分へ書き込みます。
注: スウィズルビューを介した書き込みでは、処理によって成分値が変化しない場合でも、 メモリ内のベクトル全体を書き込みます。スウィズルビューへの書き込みと一様性解析およびメモリモデルとの相互作用については、 以下の説明を参照してください。
入力:
型 swizzle<AS,S,N,K> のスウィズルビュー (p, IndexList)
型 vecN<S> のベクトル old_contents
old_contents は、過去のある時点で p が参照するメモリに 格納されていたベクトルであることを意図しています。
型 vecK<S> のベクトル update
IndexList 内のすべてのインデックスは、互いに異なっていなければなりません。 この要件は K ≤ N を含意します。
変数:
型 vecN<S> の new
手順:
慣例により、IndexList = « Idx0, ..., IdxK−1 » とします
変数 new を old_contents で初期化します。
0..K-1 内の各 i について:
new の成分 Idxi を、 update の成分 i の値に設定します。 インデックス構文を使用すると: new[Idxi] = update[i]。
new を p が参照するメモリへ書き込みます。
注: すべての Idxi が異なることを要求することで、 ステップ3が new の各成分を最大1回だけ更新することが保証されます。
注: ステップ2と3は、次の宣言的な規則で置き換えることができます:型 vecN<S> のベクトル new を形成します。 new の成分 i は、次のとおりです:
0...K−1 内のいずれかの j について i = Idxj である場合、 update の成分 j。
それ以外の場合、old_contents の成分 i。
スウィズルビューはスウィズルビュー型を持ちます:
| 制約 | 型 | 説明 |
|---|---|---|
|
S は具象スカラー型、 N と K は、 vecN<S> と vecK<S> の両方が 有効なベクトル型となる整数。 ptr<AS,vecN<S>,read_write> は 有効なポインター型。 | swizzle<AS,S,N,K> |
スウィズル
ビュー型は、次の条件を満たすスウィズルビュー
(p, IndexList) の集合と同一視されます:
スウィズルビュー型は WGSL ソース内には記述されず、 代わりに WGSL モジュールの解析に使用されます。 |
スウィズルビューは、次の方法で形成されます:
-
read_write アクセスモードを持ち、 格納型がベクトルである参照値またはポインター値へ、 複数文字のスウィズル名を適用する、または
-
スウィズルビューへ複数文字のスウィズル名を適用する。
これらの規則により、スウィズルビューの IndexList 部分は、 シェーダー作成時に完全に決定されます。
詳細については、§ 8.6 スウィズルビュー式を参照してください。
fn swizzle_read_and_write () { var v : vec4u; // v.y = 1; v.z = 2; と同じ。 // ただし、ベクトルのメモリからの読み取りとメモリへの書き込みは、それぞれ正確に1回だけ行われる。 v . yz = vec2u( 1 , 2 ); // let u = vec3(v.a, v.g, v.b); と同じ。 // 式 v.agb は型 swizzle<function,u32,4,3> のスウィズルビューである。 // let 宣言の実効値型は、具象で構築可能な型または // ポインター型でなければならない。そのため、スウィズルビューのロード規則を呼び出すことにより、 // スウィズルビューは自動的に vec3u へ変換される。 let u = v . agb ; // スウィズルは連鎖できる。 // v.zy = vec2(99,100); と同じ。 v . yz . yx = vec2( 99 , 100 ); // スウィズルビューへ1文字を適用すると、基となるベクトルの // スカラー成分への参照が得られる。 // v.z = 99; と同じ。 v . yz . y = 99 ; // スウィズルビューへインデックスを付けると、ベクトルの成分の1つへの参照が得られる。 // これは1文字のベクトルアクセスを形成するかのように動作するが、 // インデックスによって、スウィズル名のどの文字を使用するかが選択される。 v . zy [ 1 ] = 50 ; // v.y = 50; と同じ。 }
// この例では、swizzle_assignment に加えて pointer_composite_access のサポートを前提とする。 requires pointer_composite_access ; fn swizzle_read_and_write_via_pointer ( p : ptr< function, vec4u> ) { // (*p).y = 1; (*p).z = 2; と同じ。 p . yz = vec2u( 1 , 2 ); // let u = vec3((*p).a, (*p).g, (*p).b); と同じ。 let u = p . agb ; // スウィズルは連鎖できる。 // p.zy = vec2(99,100); と同じ。 p . yz . yx = vec2( 99 , 100 ); // ポインターからスウィズルビューを構築できる。 // スウィズルビューへ1文字を適用すると、基となるベクトルの // スカラー成分への参照が得られる。 // (*p).z = 99; と同じ。 p . yz . y = 99 ; // スウィズルビューへインデックスを付けると、ベクトルの成分の1つへの参照が得られる。 // これは1文字のベクトルアクセスを形成するかのように動作するが、 // インデックスによって、スウィズル名のどの文字を使用するかが選択される。 p . zy [ 1 ] = 50 ; // (*p).y = 50; と同じ。 }
fn invalid_swizzle_cases () { var v : vec2u; // 無効:成分を繰り返すスウィズルには代入できない v . xx = vec2u( 1 , 2 ); // 無効:'z' は対象ベクトルの範囲外。 v . xz = vec2u( 1 , 2 ); let u = v . xz ; // 無効:文字体系 xyzw と rgba を混在させてはならない v . xr = vec2u( 1 , 2 ); // スウィズルビューのアドレスを取得することはできない。 // ここで、v.xy はスウィズルビュー (&v,`01`) である // & 演算子はスウィズルビューに適用できないため、型検査は失敗する。 let p = & v . xy ; }
一様性解析では、スウィズルビュー書き込みは、 更新された成分の値の一様性にのみ影響を与えることができます。 これが、完全スウィズルビューと部分スウィズルビューを 区別する理由です。
ただし、基となるベクトルのすべての成分を書き込むことは、メモリモデルにとって重要です。 メモリ内の同じベクトルの異なる成分を並行して更新する2つの異なる呼び出しは、 データ競合を引き起こします。
var < workgroup> w : vec4u; @compute @workgroup_size ( 2 ) fn this_races ( @builtin ( local_invocation_index) gid : u32) { if ( gid == 0 ) { w . xy = vec2u( 0 , 1 ); // ベクトル全体を書き込み、他の呼び出しと競合する。 } else { w . zw = vec2u( 2 , 3 ); // ベクトル全体を書き込み、他の呼び出しと競合する。 } }
6.5.5. 有効および無効なメモリ参照
参照の形成については、§ 6.5.9 参照値とポインター値の形成で 詳細に説明します。 一般に、有効な参照は、次の方法で形成されます:
-
変数を名前で指定する、または
一般に、無効なメモリ参照は、次の方法で形成されます:
-
無効なポインターへ間接参照演算子を適用する、または
無効なポインターは、次の方法で形成されます:
-
bufferView またはbufferArrayView 組み込み関数を呼び出したとき、結果のポインターのメモリビューが、 バッファポインター引数のメモリビューの範囲外にあるメモリ位置を含むことになる場合。
有効なポインターは、有効な参照に対応するポインターです。
有効なスウィズルビューは、ポインター値が有効なスウィズルビューです。 無効なスウィズル ビューは、ポインター値が無効なスウィズルビューです。
6.5.6. 起点変数
ポインター値の起点変数は、 対応する参照値の起点変数として定義されます。
スウィズルビューの起点 変数は、そのスウィズルビューのポインターの起点変数として定義されます。
注: 起点変数は動的な概念です。 関数の仮パラメーターの起点変数は、その関数の呼び出し箇所に依存します。 呼び出し箇所が異なれば、異なる起点変数内へのポインターが渡される場合があります。
有効な参照は常に、 ある変数の一部またはすべてのメモリ位置に対する空でないメモリビューに対応します。
有効なスウィズルビューは常に、 ある変数内のベクトルのメモリ位置に対応します。
次の例では、参照 the_particle.position[i] は、
i が 0 または 1 である場合に限り有効です。
i が 2 の場合、この参照は無効なメモリ
参照になりますが、それ以外の点では
the_particle.color_index のメモリ位置に対応します。
6.5.7. 範囲外アクセス
無効なメモリ参照または無効なスウィズルビューへアクセスする演算は、 範囲外アクセスです。
範囲外アクセスはプログラムの欠陥です。記述どおりに実行された場合、通常は次の結果になるためです:
このため、実装は記述どおりにアクセスを実行しません。 範囲外アクセスを実行すると、 動的エラーが発生します。
注: 格納型を誤って解釈する例は、
前節の例で発生します。
i が 2 の場合、式 the_particle.velocity[i] の型は
ref<storage,f32,read_write> です。これは、f32 を格納型とするメモリビューであることを意味します。
しかし、このメモリ位置は color_index メンバーに割り当てられているため、
格納されている値の実際の型は i32 です。
そのような結果には、次のものが含まれますが、これらに限定されません:
- トラップ
-
シェーダーの呼び出しは直ちに終了し、シェーダーステージの出力は ゼロ値に設定されます。
- 無効なロード
-
無効な参照からのロードは、次のいずれかを返す場合があります:
-
起点変数がuniform バッファまたはストレージバッファである場合、 起点変数へバインドされた WebGPU の
GPUBuffer内にある任意のメモリ位置の値 -
起点変数がuniform バッファまたはストレージバッファでない場合、 起点変数内の任意のメモリ位置の値
-
参照の格納型に対するゼロ値
-
ロードされた値がベクトルである場合、値 (0, 0, 0, x)。ここで x は:
-
整数成分の場合、0、1、または最大の正の値
-
浮動小数点成分の場合、0.0 または 1.0
-
-
- 無効なストア
-
無効な参照へのストアでは、次のいずれかが行われる場合があります:
-
起点変数がストレージ バッファである場合、 起点変数へバインドされた WebGPU の
GPUBuffer内にある任意のメモリ位置へ値を格納する -
起点変数がストレージ バッファでない場合、 起点変数内の任意のメモリ位置へ値を格納する
-
実行しない。
-
無効なロードまたはストアが、共有アドレス空間内にある変数の別の位置へのアクセスに振り替えられた場合、 データ競合が発生することがあります。 たとえば、並行して実行される複数の呼び出しによるアクセスが、 配列の最初の要素へ振り替えられる場合があります。 少なくとも1つのアクセスが書き込みであり、それ以外の方法で同期されていない場合、 結果はデータ競合となるため、動的エラーになります。
範囲外アクセスは、一様性解析の前提を無効にします。 たとえば、範囲外アクセスによって呼び出しが早期終了すると、 その呼び出しは集合演算に参加できなくなります。 特に、workgroupBarrier の呼び出しによって シェーダーが停止する可能性があり、導関数が無効な結果を生成する場合があります。
6.5.8. 参照とポインターのユースケース
参照とポインターは、その使用方法によって区別されます:
-
変数の型は参照型です。
-
アドレス取得演算(単項
&)は、 参照値を対応するポインター値へ変換します。 -
間接参照演算(単項
*)は、 ポインター値を対応する参照値へ変換します。 -
let 宣言はポインター型にできますが、 参照型にはできません。
-
仮 パラメーターはポインター型にできますが、参照型にはできません。
-
単純 代入文は、参照を介してメモリの内容を更新する書き込みアクセスを実行します。ここで:
-
単純代入文の左辺は、 アクセスモードが write または read_write である 参照型でなければなりません。
-
単純代入文の右辺を評価した結果は、 左辺の格納型にならなければなりません。
-
-
スウィズルビューは、 read_write アクセスモードを持ち、 格納型がベクトルである参照値またはポインター値へ、 複数文字のスウィズル名を適用することで形成できます。
-
スウィズル 代入文は、スウィズルビューを介して、 メモリ内のベクトルの2個以上の成分を更新します。
-
スウィズルビューは、上記のようにポインターまたは参照から、 あるいは別のスウィズルビューから作成されます。 § 8.6 スウィズルビュー式を参照してください。
-
-
ロード規則: 関数内では、型規則を満たすために参照が自動的に間接参照されます(読み取られます):
-
関数内で、格納型 T を持つ参照式 r が 文または式で使用され、次の条件を満たす場合:
-
r のアクセスモードが read または read_write であり、かつ
-
一致する可能性がある型規則が、r に型 T の値を要求するものだけである、
-
-
その型規則の要件は満たされたものとみなされ、かつ
-
その文脈で r を評価した結果は、評価時に r が参照するメモリ位置に格納されている値(型 T)です。 すなわち、結果値を生成するために読み取り アクセスが実行されます。
-
-
同様に、スウィズルビューのロード規則があります: 関数内では、型規則を満たすためにスウィズルビュー読み取りが実行されます:
-
関数内でスウィズルビュー sv が 文または式で使用され、次の条件を満たす場合:
-
sv が (p, IndexList) であり、 型 swizzle<AS,S,N,K> を持ち、かつ
-
一致する可能性がある型規則が、sv に 型 vecK<S> の値を要求するものだけである、
-
-
その型規則の要件は満たされたものとみなされ、かつ
-
その文脈で sv を評価した結果は、その時点で sv に対してスウィズルビュー読み取りを実行した結果です。
-
結果値の型は vecK<S> です。
-
この演算は、p が参照するベクトル全体に対して1回の読み取りアクセスを実行します。
-
-
このように参照を定義することで、変数を単純かつ慣用的に使用できます:
@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' が、 // 評価時点で '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> である。 // 参照の格納型が式に要求される型と一致し、他の型規則が // 適用されないため、ロード規則を適用する。 // この文脈での 'age' の評価結果は、return 文が実行された時点で // 'age' が参照するメモリ位置からロードされた // i32 値である。 return age ; } fn caller () { age = 21 ; // 定数 copy_age は i32 値 21 を取得する。 let copy_age : i32= get_age (); }
このようにポインターを定義することで、2つの主要なユースケースが可能になります:
-
ポインター型の let 宣言を使用し、変数の内容の一部に対する短い名前を形成する。
-
関数の仮パラメーターを使用して、呼び出し元関数からアクセス可能な 変数のメモリを参照する。
-
そのような関数の呼び出しは、そのオペランドとしてポインター値を提供しなければなりません。 これには多くの場合、変数の内容へのポインターを取得するために、 アドレス取得演算(単項
&)を使用する必要があります。
-
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 () { // storage メモリ内の特定の 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' に '*x' の格納型である i32 型を要求する。そのためロード規則が 適用され、'*x' は評価時に '*x' のメモリへ格納されている値、 すなわち 0 に対応する i32 値へ評価される。 - 0 に 1 を加え、右辺の最終値 1 を生成する。 */ '*x' のメモリへ 1 を格納する。 */ * 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.5.9. 参照値とポインター値の形成
参照値は、次のいずれかの方法で形成されます:
-
ポインターへ間接参照(単項
*)演算を使用します。 -
複合値へのメモリビューまたはスウィズル ビューに対して名前付き成分式を使用します:
-
ベクトル格納型を持つメモリビューまたは スウィズルビューが与えられた場合、1文字のベクトルアクセス句を付加すると、 ベクトルの名前付き成分への参照が得られます。 § 8.5.1.3 ベクトルメモリビューまたは スウィズルビューからの成分参照を参照してください。
-
構造体格納型を持つメモリビューが与えられた場合、 メンバーアクセス句を付加すると、構造体の名前付きメンバーへの参照が得られます。 § 8.5.4 構造体アクセス式を参照してください。
-
-
複合値へのメモリビューまたはスウィズルビューに対してインデックス 式を使用します:
-
ベクトル格納型を持つメモリビューが与えられた場合、 配列インデックスアクセス句を付加すると、ベクトルのインデックス指定された成分への参照が得られます。 § 8.5.1.3 ベクトルメモリビューまたは スウィズルビューからの成分参照を参照してください。
-
スウィズルビューが与えられた場合、配列インデックスアクセス句を付加すると、 ベクトルの成分への参照が得られます。 この場合、インデックス指定は間接的です。 指定されたインデックスは、成分のインデックスとして使用する スウィズルビューの IndexList のメンバーを選択します。 § 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' ベクトルアクセス句を適用し、前のステップの // 参照値が指すベクトルの最初の成分のメモリへの // 参照を生成する。 // 結果の型は ref<function,f32,read_write>。 // 代入の右辺を評価すると f32 値 1.0 が得られる。 // f32 値 1.0 を uv.x が参照する storage メモリ位置へ格納する。 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 が得られる。 // f32 値 2.0 を uv[1] が参照する storage メモリ位置へ格納する。 uv [ 1 ] = 2.0 ; var m : mat3x2< f32> ; // 'm[2]' を評価するとき: // 1. まず 'm' を評価し、変数 'm' のメモリへの参照を生成する。 // 結果の型は ref<function,mat3x2<f32>,read_write>。 // 2. 次に '[2]' 配列インデックス句を適用し、前のステップの // 参照値が指す3番目の列ベクトルのメモリへの // 参照を生成する。 // したがって式 'm[2]' の型は ref<function,vec2<f32>,read_write>。 // 'let' 宣言は型 vec2<f32> に対するものであるため、宣言文は // 初期化子に型 vec2<f32> を要求する。 // (他の型規則を適用できないため)ロード規則が適用され、 // 初期化子の評価によって、宣言が実行された時点で 'm[2]' が // 参照するメモリ位置からロードされた vec2<f32> 値が // 得られる。 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 を要求する。 // (他の型規則を適用できないため)ロード規則が適用され、 // 初期化子の評価によって、宣言が実行された時点で // 'A[4]' が参照するメモリ位置からロードされた // i32 値が得られる。 let A_4_value : i32= A [ 4 ]; // 'person.weight' を評価するとき // 1. まず 'person' を評価し、モジュールスコープで宣言された // 変数 'person' のメモリへの参照を生成する。 // 結果の型は ref<private,S,read_write>。 // 2. 次に '.weight' メンバーアクセス句を適用し、前のステップの // 参照値が参照するメモリの2番目のメンバーの // メモリへの参照を生成する。 // 結果の型は ref<private,f32,read_write>。 // let 宣言は右辺に型 f32 を要求する。 // (他の型規則を適用できないため)ロード規則が適用され、 // 初期化子の評価によって、宣言が実行された時点で // 'person.weight' が参照するメモリ位置からロードされた // f32 値が得られる。 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) が得られる。 // 値 (1.0, 2.0) を uv が参照する storage メモリ位置へ格納する。 * uv_ptr = vec2f( 1.0 , 2.0 ); // 代入の左辺を評価する: // 'uv_ptr.x' を評価して参照を生成する: // 1. まず 'uv_ptr' を評価し、変数 'uv' のメモリへのポインターを生成する。 // 結果の型は ptr<function,vec2<f32>,read_write>。 // 2. 次に '.x' ベクトルアクセス句を適用し、前のステップの // 参照値が指すベクトルの最初の成分のメモリへの // 参照を生成する。 // 結果の型は ref<function,f32,read_write>。 // 代入の右辺を評価すると f32 値 1.0 が得られる。 // f32 値 1.0 を uv.x が参照する storage メモリ位置へ格納する。 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 が得られる。 // f32 値 2.0 を uv[1] が参照する storage メモリ位置へ格納する。 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番目の列ベクトルのメモリへの // 参照を生成する。 // したがって式 'm[2]' の型は ref<function,vec2<f32>,read_write>。 // 'let' 宣言は型 vec2<f32> に対するものであるため、宣言文は // 初期化子に型 vec2<f32> を要求する。 // (他の型規則を適用できないため)ロード規則が適用され、 // 初期化子の評価によって、宣言が実行された時点で 'm[2]' が // 参照するメモリ位置からロードされた vec2<f32> 値が // 得られる。 let p_m_col2 : vec2< f32> = m_ptr [ 2 ]; let A_ptr = & A ; // 'A[4]' を評価するとき // 1. まず 'A' を評価し、変数 'A' のメモリへのポインターを生成する。 // 結果の型は ptr<function,array<i32,5>,read_write>。 // 2. 次に '[4]' 配列インデックス句を適用し、前のステップの // 参照値が参照する配列の5番目の要素のメモリへの // 参照を生成する。 // 結果値の型は ref<function,i32,read_write>。 // let 宣言は右辺に型 i32 を要求する。 // (他の型規則を適用できないため)ロード規則が適用され、 // 初期化子の評価によって、宣言が実行された時点で // 'A[4]' が参照するメモリ位置からロードされた // i32 値が得られる。 let A_4_value : i32= A_ptr [ 4 ]; let person_ptr = & person ; // 'person.weight' を評価するとき // 1. まず 'person_ptr' を評価し、モジュールスコープで宣言された // 変数 'person' のメモリへのポインターを生成する。 // 結果の型は ptr<private,S,read_write>。 // 2. 次に '.weight' メンバーアクセス句を適用し、前のステップの // 参照値が参照するメモリの2番目のメンバーの // メモリへの参照を生成する。 // 結果の型は ref<private,f32,read_write>。 // let 宣言は右辺に型 f32 を要求する。 // (他の型規則を適用できないため)ロード規則が適用され、 // 初期化子の評価によって、宣言が実行された時点で // 'person.weight' が参照するメモリ位置からロードされた // f32 値が得られる。 let person_weight : f32= person_ptr . weight ; }
ポインター値は、次のいずれかの方法で形成されます:
-
参照に対してアドレス取得演算子(単項
&)を使用します。 -
関数の仮 パラメーターがポインター型を持つ場合、 実行時にその関数が呼び出されると、仮パラメーターの使用は、 呼び出し元関数の呼び出し箇所で 対応するオペランドへ提供されたポインター値を表します。
-
bufferView または bufferArrayView 組み込み関数呼び出しの結果。
すべての場合において、結果のアクセスモードは、元のポインターのアクセスモードと同じです。
// f32 値を格納するため、private アドレス空間内に変数を宣言する。 var < private> x : f32; fn f () { // i32 値を格納するため、function アドレス空間内に変数を宣言する。 var y : i32; // 名前 'x' はモジュールスコープの変数 'x' へ解決され、 // 参照型 ref<private,f32,read_write> を持つ。 // 単項 '&' 演算子を適用すると、参照がポインターへ変換される。 // アクセスモードは元の変数のアクセスモードと同じであるため、 // 完全に指定された型は ptr<private,f32,read_write> となる。ただし、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' は、前の文で宣言された関数スコープの変数 'x' へ解決され、 // 型 ref<function,u32,read_write> を持つ。 // 単項 '&' 演算子を適用すると、参照がポインターへ変換される。 // アクセスモードの既定値は 'read_write'。 let inner_x_ptr : ptr< function, u32> = & x ; }
6.5.10. 他の言語における参照およびポインターとの比較
この節は参考情報であり、規範的ではありません。
WGSL の参照とポインターは、他の言語よりも制限されています。 特に:
-
WGSL では、変数としても仮パラメーターとしても、 参照を別の参照または変数へのエイリアスとして直接宣言することはできません。
-
WGSL では、ポインターと参照は格納可能ではありません。 すなわち、WGSL の変数宣言の内容に、 ポインターまたは参照を含めることはできません。
-
WGSL では、関数がポインターまたは参照を返してはなりません。
-
WGSL には、整数値とポインター値の間で変換する方法はありません。
-
WGSL には、ポインター値の型を別のポインター型へ強制的に変更する方法はありません。
-
複合値の成分参照式は異なります。 これは複合値への参照を受け取り、複合値内の成分または要素の1つへの参照を生成します。 実装上のより低い抽象化レベルでは同じ機械アドレスを持つ場合がありますが、 WGSL ではこれらを異なる参照とみなします。
-
-
WGSL には、参照値の型を別の参照型へ強制的に変更する方法はありません。
-
WGSL には、ポインターまたは参照のアクセスモードを変更する方法はありません。
-
比較すると、C++ は非 const ポインターを const ポインターへ自動変換し、 const 値を非 const 値へ変換するための
const_castを備えています。
-
-
WGSL には、「ヒープ」から新しいメモリを割り当てる方法はありません。
-
WGSL には、変数を明示的に破棄する方法はありません。 WGSL 変数のメモリへアクセスできなくなるのは、その変数がスコープ外になったときだけです。
注: 上記の規則から、 「ダングリング」ポインター、すなわち「生存している」起点変数のメモリを参照しないポインターを 形成することはできません。 メモリビューが無効な メモリ参照である場合はありますが、 起点変数またはバッファに関連付けられていないメモリ 位置へアクセスすることは決してありません。
6.6. テクスチャ型およびサンプラー型
テクセルは、テクスチャの独立してアクセス可能な最小要素として使用されるスカラーまたはベクトルである。 テクセルという語は、テクスチャ要素を短縮したものである。
テクスチャは、 レンダリングに役立つ特殊な操作をサポートするテクセルの集合である。 WGSL では、それらの操作はテクスチャ組み込み関数を介して呼び出される。 完全な一覧については、§ 17.7 テクスチャ組み込み関数を参照のこと。
WGSL テクスチャは、WebGPU のGPUTextureに対応する。
テクスチャには、次の特性がある:
- テクセル形式
-
各テクセルのデータ表現。§ 6.6.1 テクセル形式を参照のこと。
- 次元数
-
グリッド座標の次元数、および座標の解釈方法。 次元数は 1、2、または 3 である。 ほとんどのテクスチャはデカルト座標を使用する。 キューブテクスチャには 6 つの正方形の面があり、 原点を中心とする立方体に向かう、原点からの方向ベクトルとして解釈される 3 次元座標によってサンプリングされる。
GPUTextureViewDimensionを参照のこと。 - サイズ
-
各次元に沿ったグリッド座標の範囲。これはミップレベルの関数である。
- ミップレベル数
-
ミップレベル数は、サンプリングテクスチャおよび深度テクスチャでは 1 以上であり、 ストレージ テクスチャでは 1 に等しい。
ミップレベル 0 には、 テクスチャのフルサイズ版が格納される。 後続の各ミップレベルには、前のミップレベルをフィルタリングしたものが、 前のミップレベルの半分のサイズ(丸めの範囲内)で格納される。
テクスチャをサンプリングするときは、明示的または暗黙的に計算された詳細度を使用して、 テクセルデータを読み取るミップレベルを選択する。次に、これらが フィルタリングによって結合され、サンプリング値が生成される。 - 配列化
-
テクスチャが配列化されているかどうか。
-
配列化されていないテクスチャは、テクセルのグリッドである。
-
配列化されたテクスチャは、テクセルのグリッドからなる同種配列である。
-
- 配列サイズ
-
テクスチャが配列化されている場合の、同種グリッドの数。
- サンプル数
-
テクスチャがマルチサンプルの場合のサンプル数。
テクスチャ内の各テクセルには、一意の論理テクセルアドレスが関連付けられる。 これは、次の要素を持つ整数タプルである:
テクスチャの物理的な構成は、通常、レンダリング操作向けに最適化されている。 これを実現するため、データレイアウト、データ型、およびシェーダー言語で直接表現できない 内部操作を含む多くの詳細が、プログラマーから隠されている。
その結果、シェーダーはテクスチャ変数内のテクセルメモリへ直接アクセスできない。 代わりに、アクセスは不透明なハンドルを介して行われる:
-
シェーダー内では:
-
WebGPU パイプラインを構築するとき、テクスチャ変数の格納型およびバインディングは、 対応するバインドグループレイアウトエントリーと互換性がなければならない。
このように、テクスチャ型でサポートされる操作の集合は、 そのテクスチャ型を持つ形式パラメーターを備えた テクスチャ組み込み関数が利用可能かどうかによって決まる。
注: テクスチャ変数に格納されたハンドルは、 シェーダーによって変更できない。 つまり、アクセス先となる基礎テクスチャが変更可能である場合(たとえば、書き込み専用の ストレージテクスチャ)でも、この変数は読み取り専用である。
テクスチャ型とは、 次の各節で定義される型の集合である:
サンプラーは、 サンプリング テクスチャまたは深度テクスチャからテクセルへアクセスする方法を制御する 不透明なハンドルである。
WGSL サンプラーは、WebGPU のGPUSamplerに対応する。
テクセルへのアクセスは、サンプラーの複数のプロパティを介して制御される:
- アドレスモード
-
テクスチャの境界および範囲外の座標を どのように解決するかを制御する。 各テクスチャ次元のアドレスモードは、個別に設定できる。 WebGPU の
GPUAddressModeを参照のこと。 - フィルターモード
-
最終結果を生成するために、どのテクセルへアクセスするかを制御する。 フィルタリングでは、最も近いテクセルを使用することも、複数の テクセル間を補間することもできる。 複数のフィルターモードを個別に設定できる。 WebGPU の
GPUFilterModeを参照のこと。 - LOD クランプ
-
アクセスする詳細度の最小値と最大値を制御する。
- 比較
-
比較サンプラーで行われる比較の種類を制御する。 WebGPU の
GPUCompareFunctionを参照のこと。 - 最大異方性
-
サンプラーが使用する異方性の最大値を制御する。
サンプラーは WGSL モジュール内で作成できず、その状態(たとえば、 上記のプロパティ)はシェーダー内では不変であり、 WebGPU API によってのみ設定できる。
補間フィルタリングを使用する任意のサンプラー(すなわち、フィルタリングサンプラー)が、 フィルタリング不可能な形式のテクスチャとともに使用された場合、 パイプライン作成エラーとなる。
注: サンプラー変数に格納されたハンドルは、 シェーダーによって変更できない。
6.6.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)
|
ストレージテクスチャのテクセル形式表に列挙されているテクセル形式は、
少なくとも 1 つのアクセス
モードで WebGPU のSTORAGE_BINDING
用途をサポートするWebGPU のプレーンカラー形式に対応する。
これらのテクセル形式は、§ 6.6.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.6.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はサンプリング 型である。
-
画像のパラメーター化された型は、サンプリングからの変換後の型である。 たとえば、8 ビット unorm 成分を持つテクセルからなる画像を使用できるが、それらをサンプリングすると、 32 ビット浮動小数点の結果(または f32 のベクトル)が得られる。
6.6.3. マルチサンプルテクスチャ型
マルチサンプルテクスチャは、 1 以上のサンプル数を持つ。 名前に反して、サンプラーとともに使用することはできない。 サンプルインデックスを無視した場合、実質的には 論理テクセル アドレスごとに複数のテクセル分の データを格納する。
テクセル形式は、
テクスチャ変数にバインドされたGPUTextureの
format
属性である。
WebGPU は、テクスチャ、バインドグループレイアウトのsampleType、
およびテクスチャ変数のサンプリング型の間の
互換性を検証する。
texture_multisampled_2dはサンプリング型によってパラメーター化され、
f32、i32、または u32 でなければならない。
| 型 | 次元数 | 配列化 |
|---|---|---|
| texture_multisampled_2d<T> | 2D
| いいえ |
| texture_depth_multisampled_2d | 2D
| いいえ |
-
Tはサンプリング 型である。
6.6.4. 外部サンプリングテクスチャ型
外部テクスチャは、
texture_2d<f32>に似ているものの、異なる表現を持つ可能性がある、
不透明な 2 次元浮動小数点サンプリングテクスチャ型である。
これは、異なる表現を処理するtextureLoadまたは
textureSampleBaseClampToEdge組み込み
関数を使用して読み取ることができる。
WebGPU § 6.4 GPUExternalTextureを参照のこと。
| 型 | 次元数 | 配列化 |
|---|---|---|
| texture_external | 2D
| いいえ |
6.6.5. ストレージテクスチャ型
ストレージテクスチャは、サンプラーを使用せずに 個々のテクセル値へアクセスすることをサポートする。
-
書き込み専用ストレージテクスチャは、 シェーダー値を格納テクセル値へ自動的に変換しながら、 個々のテクセルへ書き込むことをサポートする。
-
読み取り専用ストレージテクスチャは、 格納テクセル値をシェーダーテクセル値へ自動的に変換しながら、 個々のテクセルを読み取ることをサポートする。
-
読み書き可能なストレージテクスチャは、 シェーダー値と格納テクセル値の間で自動的に変換しながら、個々の テクセルを読み取り、書き込むことをサポートする。
ストレージテクスチャ型は、ストレージテクスチャのテクセル形式のいずれかによって パラメーター化されなければならない。 テクセル形式によって、§ 6.6.1 テクセル 形式で指定される変換関数が決まる。
ストレージテクスチャにテクセルを書き込む場合、変換関数の逆関数を使用して、 シェーダー値を格納テクセルへ変換する。
| 型 | 次元数 | 配列化 |
|---|---|---|
| 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は、ストレージテクスチャのテクセル 形式のいずれかに対する列挙子でなければならない
-
FormatとAccessの組み合わせが無効であることを原因とする シェーダー作成エラーは発生しない。 FormatとAccessの組み合わせは、パイプライン作成中の シェーダーバインディング検証 ステップで検査される。 無効な組み合わせは、パイプライン作成 エラーを引き起こす。
6.6.6. 深度テクスチャ型
深度テクスチャは、 sampler_comparisonと組み合わせて アクセスできる。 サンプラーを使用せずにアクセスすることもできる。 深度テクスチャでは、読み取り アクセスのみが許可される。
テクスチャのテクセル形式は、
GPUTextureBindingLayoutで定義される。
| 型 | 次元数 | 配列化 |
|---|---|---|
| texture_depth_2d | 2D
| いいえ |
| texture_depth_2d_array | 2D
| はい |
| texture_depth_cube | Cube
| いいえ |
| texture_depth_cube_array | Cube
| はい |
6.6.7. サンプラー型
サンプラーは、 サンプリングテクスチャ または 深度テクスチャへのアクセスを、 次の操作の組み合わせを実行することによって仲介する:
-
座標変換。
-
必要に応じたミップレベル選択の変更。
-
サンプリング テクスチャの場合、必要に応じて取得したテクセル値をフィルタリングする。
-
深度 テクスチャの場合、取得したテクセルに適用する比較関数を決定する。
サンプラー型は次のとおりである:
| 型 | 説明 |
|---|---|
| sampler | サンプラー。サンプリングテクスチャへのアクセスを仲介する。 |
| sampler_comparison | 比較サンプラー。 深度テクスチャへのアクセスを仲介する。 |
サンプラーは、WebGPU API で作成されるときにパラメーター化される。 WGSL モジュールによって変更することはできない。
サンプラーは、テクスチャ組み込み関数でのみ使用できる。
sampler sampler_comparison
6.7. AllTypes 型
AllTypes型は、 すべての WGSL 型の集合である。
WGSL ソース内で AllTypes 型を記述する方法はない。
すべての事前宣言された型および 型ジェネレーターの一覧については、 § 6.10 事前宣言された型および型ジェネレーターの概要を参照のこと。
代わりに、AllTypes 型は、通常の値を含む可能性があるあらゆる句に 型検査規則が適用されるようにするために存在する。 WGSL は、型を値の一種として定義し、式が型を表せるようにすることで、 規則の一貫性を保つ。
その動機となる事例はテンプレートパラメーターであり、これはさまざまな文脈で、 型、列挙子、またはプレーン値を含む、 複数種類のものを表すことがある。 特に、template_arg_expression文法規則は、 expression文法 非終端記号に展開される。
6.8. 型エイリアス
型エイリアスは、 既存の型に対する新しい名前を宣言する。 宣言はモジュールスコープに現れなければならず、そのスコープはプログラム全体である。
型 T が構造体型 S の型 エイリアスとして定義されている場合、 属性を含む S のメンバーのすべての特性が、T のメンバーに引き継がれる。
注: エイリアスの対象となる型が値コンストラクター 組み込み関数をサポートする場合、 型エイリアスがスコープ内にあり、それ以外の点でも関数の呼び出しが有効であるときは、 元の型指定子名の代わりにエイリアス名を介してそれらの関数を呼び出せる。
'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.9. 型指定子の文法
§ 8.18 型式を参照のこと。
注: 式は、primary_expression文法規則を介してtemplate_elaborated_identへ展開すること、および 括弧で囲むことによって、型を表すこともできる。
6.10. 事前宣言された型と型ジェネレーターの概要
WGSL ソースで記述できる事前宣言された 型は次のとおりである:
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.5.3 参照型およびポインター型を参照のこと |
| texture_1d | § 6.6.2 サンプリングテクスチャ型を参照のこと |
| texture_2d | |
| texture_2d_array | |
| texture_3d | |
| texture_cube | |
| texture_cube_array | |
| texture_multisampled_2d | § 6.6.3 マルチサンプルテクスチャ型を参照のこと |
| texture_storage_1d | § 6.6.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 式 | いいえ |
| override | 不変 | モジュール | 具象スカラー | 省略可能3 | const 式またはoverride 式 | いいえ4 |
| let | 不変 | 関数 | 具象構築可能型または ポインター型。 さらに、texture_and_sampler_let機能が サポートされている場合は、テクスチャ型またはサンプラー型。 | 必須 | const 式、override 式、または ランタイム 式 | いいえ |
|
var<storage, read> var<storage> | 不変 | モジュール | 具象ホスト共有可能型 | 禁止 | はい。 ストレージ バッファ | |
| var<storage, read_write>5,6 | 可変 | モジュール | 具象ホスト共有可能型 | 禁止 | はい。 ストレージ バッファ | |
| var<uniform> | 不変 | モジュール | 具象構築可能かつホスト共有可能な型、 または固定サイズ バッファ | 禁止 | はい。 uniform バッファ | |
| var<immediate> | 不変 | モジュール | 具象構築可能かつホスト共有可能な型 (配列および配列メンバーを含む構造体を除く) | 禁止 | はい。 イミディエイト データ | |
| var5 | 不変7 | モジュール | テクスチャ | 禁止 | はい。 テクスチャ リソース | |
| var | 不変 | モジュール | サンプラー | 禁止 | はい。 サンプラー リソース | |
| var<workgroup>6,8 | 可変 | モジュール | 具象プレーン型であり、 固定 フットプリントを持つもの、または固定サイズバッファ9 | 禁止10 | いいえ | |
| var<private> | 可変 | モジュール | 具象構築可能型 | 省略可能10 | const 式またはoverride 式 | いいえ |
| var<function> var | 可変 | 関数 | 具象構築可能型 | 省略可能10 | const 式、override 式、または ランタイム 式 | いいえ |
-
式の型は、実効値型へ実行可能な形で 変換できなければならない。
-
初期化子が指定されていない場合、パイプライン作成時に値を指定しなければならない。
-
override 宣言はシェーダーインターフェイスの一部だが、 バインドされたリソースではない。
-
ストレージバッファおよび ストレージ テクスチャのうち、read以外のアクセスモードを持つものは、 頂点シェーダーステージで静的に アクセスできない。 WebGPU の
createBindGroupLayout()を参照のこと。 -
アトミック型は、 可変ストレージバッファまたはワークグループ変数にのみ現れることができる。
-
writeまたは read_write アクセスモードを持つ ストレージテクスチャ内のデータは可変だが、 textureStore組み込み関数を介してのみ変更できる。 変数自体は変更できない。
-
workgroupアドレス空間の変数には、 コンピュートシェーダーステージでのみ静的に アクセスできる。
-
最も外側の配列の 要素数または バッファのサイズは、 override 式であってもよい。
-
初期化子がない場合、変数はデフォルト 初期化される。
7.1. 変数と値の比較
変数 宣言は、WGSL モジュール内で唯一の可変データである。 値宣言は 常に不変である。 変数には関連付けられたメモリ位置があるため、 参照値およびポインター値の基礎となることができるが、 値宣言はポインター値または参照値の基礎にはなれない。
一般に、変数を使用することは値宣言を使用するよりもコストが高い。 これは、変数を使用するには、その変数に関連付けられたメモリ位置を 読み取る、または書き込むための追加操作が必要になるためである。
一般的に、作成者は次の順序で宣言の使用を優先すべきである。 最も優先される選択肢を最初に示す:
通常、これによってシェーダー全体のパフォーマンスが最良となる。
7.2. 値宣言
識別子が 値宣言へ 解決される場合、 その識別子はその値を表す。
WGSL は、複数種類の値宣言を提供する。 各種類の宣言の値は、シェーダーのライフサイクルにおける 異なる時点で確定する。 値宣言の各種類と、その値が確定する時点は次のとおりである:
7.2.1. const 宣言
const 宣言は、 シェーダー作成時に確定する データ値の名前を指定する。 各 const 宣言には初期化子が必要である。 const 宣言は、モジュールスコープまたは関数スコープで宣言できる。 初期化式はconst 式でなければならない。 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 の配列: // (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 レベルで // "width" という名前を使用して指定される。 override depth : f32; // API レベルで // "depth" という名前を使用して指定される。 // オーバーライドが必須。 override height = 2 * depth ; // デフォルト値は // (API レベルで設定されていない場合) // 別のオーバーライド可能な定数に // 依存する。
7.2.3. let 宣言
let 宣言は、 実行時に文が実行されるたびに確定する値の名前を指定する。 let 宣言は、関数スコープ内でのみ宣言しなければならず、そのため 動的コンテキストである。 let 宣言には初期化式が必要である。 値は、初期化子の具象化された値である。 let 宣言の実効値型は、具象構築可能型または ポインター型のいずれかで なければならない。 texture_and_sampler_let機能が サポートされている場合、実効値型はテクスチャ型またはサンプラー型であってもよい。
注: バッファ型は構築可能ではないため、 バッファへのポインターだけを 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変数の初期化子が存在する場合、 それはconst 式またはoverride 式でなければならない。 functionまたは private以外のアドレス空間にある変数は、 初期化子を持ってはならない。
識別子が変数宣言へ 解決される場合、その識別子は 変数のメモリに対する参照メモリビューを表す式であり、 その型は変数の参照型である。 § 8.12 変数識別子式を参照のこと。
変数宣言のアドレス空間またはアクセスモードが
プログラムソースで指定される場合、それらは var キーワードの後に
テンプレートリストとして記述される:
-
アクセスモードは、 存在する場合、事前宣言されたアドレスモードの列挙子のいずれかとして、 2 番目に指定される。
-
アクセスモードが指定される場合、アドレス空間も指定されなければならない。
-
private、storage、 uniform、workgroup、およびhandleアドレス空間の変数は、 モジュールスコープでのみ宣言しなければならない。 一方、functionアドレス空間の変数は、 関数スコープでのみ宣言しなければならない。 handle および function を除くすべてのアドレス空間では、アドレス空間を指定しなければならない。 handle アドレス空間を指定してはならない。 function アドレス空間の指定は省略可能である。
アクセスモードには 常にデフォルト値があり、storageアドレス空間の変数を除き、 WGSL ソースで指定してはならない。 § 14.3 アドレス空間を参照のこと。
uniformアドレス空間の変数は、uniform バッファ変数である。 その格納型は、 ホスト共有可能な構築可能型または 固定サイズバッファ 型でなければならず、 アドレス空間のレイアウト制約を満たさなければならない。
storageアドレス空間の変数は、ストレージバッファ変数である。 その格納型は ホスト共有可能型でなければならず、 アドレス空間のレイアウト制約を満たさなければならない。 変数はreadまたはread_write アクセスモードで宣言できる。デフォルトは read である。
immediateアドレス空間の変数は、イミディエイトデータ変数である。 その格納型は、 配列および配列メンバーを含む構造体を除く、ホスト共有可能な構築可能型でなければならない。 各エントリーポイントが 静的にアクセスする イミディエイトデータ変数は、最大 1 つでなければならない。 immediate 変数の値は、WebGPU API のコマンドエンコーダーによって記録される setImmediatesコマンドを介して設定され、 シェーダーの実行中は一定のままである。 変数のサイズは、パイプラインレイアウトのimmediateSize設定によって制限される。
テクスチャリソースは、 実効値型がテクスチャ型である変数である。 これはモジュールスコープで宣言される。 これは、テクスチャ内にある基礎となる テクセルのグリッドへアクセスするために使用される 不透明なハンドルを保持する。 ハンドル自体はhandleアドレス空間にあり、常に読み取り専用である。 多くの場合、基礎となるテクセルは読み取り専用であり、テクスチャ変数は不変であるという。 書き込み専用ストレージテクスチャおよび読み書き可能なストレージ テクスチャでは、基礎となるテクセルは可変であり、慣例により テクスチャ変数も可変であるという。
サンプラーリソースは、 実効値型がサンプラー型である変数である。 これはモジュールスコープで宣言され、 handleアドレス空間に存在し、 不変である。
§ 13.3.2 リソースインターフェイスで説明するように、uniform バッファ、 ストレージバッファ、テクスチャ、およびサンプラーは、 シェーダーのリソースインターフェイスを形成する。
変数の生存期間とは、 シェーダーの実行中にメモリ位置が変数と関連付けられている期間である。 モジュールスコープ 変数の生存期間は、シェーダーステージの実行全体である。 privateおよびfunctionアドレス空間の変数には、 呼び出しごとに独立したものが存在する。 関数スコープ変数は 動的コンテキストである。 関数スコープ変数の生存期間は、そのスコープによって決まる:
-
制御が変数の宣言へ入るときに開始する。
-
名前が動的コンテキストのいずれの部分でも、もはやスコープ 内でなくなったときに終了する。 すなわち、生存期間には、名前がスコープ内にある間に呼び出されたすべての関数が含まれる。
2 つのリソース変数は、 重複するメモリ位置を持つことがあるが、 それらの変数のいずれかが可変である場合は動的エラーとなる。 生存期間が重複するその他の変数は、重複するメモリ位置を持たない。 変数の生存期間が終了すると、そのメモリを別の変数に使用できる。
注: WGSL は、変数の内容が その変数の生存期間中にのみ観測できることを保証する。
private、function、 またはworkgroupアドレス空間の変数が作成されると、 その変数は初期値を持つ。 初期化子が指定されていない場合、初期値はデフォルト 初期値となる。 初期値は次のように計算される:
-
function アドレス空間の変数の場合:
-
private アドレス空間の変数の場合:
-
それ以外の場合は、具象化された初期化式を評価した結果。 初期化子はoverride 式でなければならないため、 その値は遅くともパイプライン作成時までに確定する。
-
workgroup アドレス空間の変数の場合:
その他のアドレス空間にある変数は、描画コマンドまたはディスパッチコマンドの バインディングによって設定されるリソースである。
次の 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 バッファ // 読み書き用のストレージバッファ @group ( 0 ) @binding ( 0 ) var < storage, read_write> pbuf : array< vec2< f32>> ; // テクスチャおよびサンプラーは、常に "handle" 空間にある。 @group ( 0 ) @binding ( 1 ) var filter_params : sampler;
// ストレージバッファ @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. 式
式は、値の計算方法を指定する。
さまざまな種類の値式には、それらがいつ評価されるかと、 どれほど表現力を持てるかとの間にトレードオフがある。 評価が早いほど操作は強く制約されるが、その一方で、 値を使用できる場所は多くなる。このトレードオフにより、 値宣言の種類ごとに異なる柔軟性が生じる。 const 式および override 式は GPU での実行前に評価されるため、 最終的な GPU コードで必要なのは式の計算結果だけである。 さらに、const 式はシェーダー作成時に評価されるため、 override 式よりも多くの状況で使用できる。たとえば、 関数スコープの 変数内にある 配列のサイズを決めるために使用できる。 ランタイム 式とは、const 式でも override 式でもない式である。 ランタイム式は、シェーダーの実行中に GPU 上で計算される。 ランタイム式を使用できる文法要素は少ないものの、他のランタイム値など、 より広い種類の式から計算できる。
8.1. 早期評価式
WGSL は、実行時より前に評価できる 2 種類の式を定義する:
8.1.1. const 式
シェーダー作成 時に評価できる式は、const 式と呼ばれる。 式のすべての識別子が次のいずれかへ解決される場合、その式は const 式である:
const式の型は、作成時固定フットプリントを持つ型へ
解決されなければならない。
注: 抽象型は、const 式から推論される型になり得る。
const 式 E は、次のいずれかの場合に、かつその場合に限り評価される:
-
Eがトップレベル式である、
-
Eが式 OuterE の部分式であり、OuterEが シェーダー作成エラーを生成するために Eの評価を必要とする (たとえば、整数除算)。
注: 評価規則は、
静的型を決定するために評価が必要な部分式が存在しない限り、
短絡演算子 && および || がその右辺の部分式の評価を
防ぐことを意味する。
const 式は、WebGPU API メソッドを実装する CPU によって評価される場合がある。 したがって、AbstractFloat値に対する演算の精度要件は、 WebAssembly [WASM-CORE-2]や ECMAScript [ECMASCRIPT]など、一般的な WebGPU ランタイム環境で 求められるものより厳しくない。 具象浮動小数点型(f32 など)の精度要件は、 § 15.7.4.1 具象浮動小数点式の精度で指定される。
例:(42)は次のように解析される:
-
項
42は、値 42 のAbstractIntである。 -
その項を括弧で囲むと、値 42 を持つAbstractInt型の 新しい式
(42)が生成される。
例:-5は次のように解析される:
-
項
5は、値 5 のAbstractIntである。 -
その項の前に「
-」を付けると、値 -5 を持つAbstractInt型の 新しい式-5が生成される。
例:-2147483648は次のように解析される:
-
項
2147483648は、値 2147483648 のAbstractIntである。 この値は 32 ビット符号付き整数の範囲に収まらないことに注意。 -
その項の前に「
-」を付けると、値 -2147483648 を持つAbstractInt型の 新しい式-2147483648が生成される。
例:const minint = -2147483648;は次のように解析される:
-
上記のとおり、
-2147483648は値 -2147483648 のAbstractIntへ評価される。 -
その結果、
minintは値 -2147483648 のAbstractIntとして宣言される。
例:let minint = -2147483648;は次のように解析される:
-
上記のとおり、
-2147483648は値 -2147483648 のAbstractIntへ評価される。 -
let 宣言には明示的な型がないため、オーバーロード解決が使用される。 適用可能なオーバーロード候補では、AbstractIntから i32、u32、またはf32のいずれかへの実行可能な自動変換を使用する。 最も低いランクのものはi32への変換であるため、 AbstractInt値 -2147483648 は、 i32値 -2147483648 へ変換される。
-
その結果、
minintは i32 値 -2147483648 として宣言される。
例:false && (10i < i32(5 * 1000 * 1000 * 1000))は次のように解析される:
-
式全体が const 式である。
-
ただし、
&&演算子の短絡規則が適用される。 左辺が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 式である:
-
override 宣言、または
-
const 宣言、または
-
const 関数、または
-
型エイリアス、または
-
構造体の名前。
注: すべてのconst 式は、 override 式でもある。
const 式以外の override 式は、パイプライン 作成中にのみ、かつ API から提供された値がoverride 宣言へ代入された後にのみ、 検証または評価される。 override 宣言の値が API を介して代入される場合、 初期化式が存在しても、それは評価されない。 それ以外の場合、override 式 E は、次の条件を満たす場合に、かつその場合に限り 評価される:
-
Eが、
GPUProgrammableStageによって 指定されたエントリーポイントの シェーダーの一部を形成し、かつ: -
次のいずれかが真である:
注: すべての override 式を override 宣言の初期化子として使用できるとは限らない。 そのような初期化子は具象スカラー型へ解決される必要があるためである。
例:override x = 42;は次のように解析される:
-
項
42は、値 42 のAbstractIntである。 -
override 宣言では、具象スカラー型が必要となる。
例:let y = x + 1;は次のように解析される:
-
上記から、
xの型はi32である。 -
式
x + 1は、override 宣言と整数リテラルから構成されるため、 override 式である。 -
この式はi32型を持ち、 パイプライン作成時に評価される。 その値は、パイプライン作成時に
xがオーバーライドされるかどうかに依存する。
例:vec3(x,x,x)は次のように解析される:
-
上記から、
xは型i32を持つ override 宣言である。 -
vec3(x,x,x)は、識別子がいずれも override 宣言へ 解決されるため、 override 式である。
override a : i32= 0 ; override b = a / 0 ; // シェーダー作成エラー。 // c のオーバーライドを試みるかどうかには関係しない
override a : i32= 0 ; override b = 1 / a ; // b は frag1 シェーダーの一部である。frag1 をパイプラインへコンパイルするとき、 // 次の場合が発生する可能性がある: // * b がオーバーライドされる場合、エラーは発生しない。 // * a がゼロ以外の値へオーバーライドされる場合、エラーは発生しない。 // * a が 0 で、b がオーバーライドされない場合、パイプライン作成エラーが発生する。 @fragment fn frag1 () { _ = b ; } // b は frag2 シェーダーの一部ではない。frag2 をパイプラインへコンパイルするとき、 // b がオーバーライドされず、a の値が 0 であっても、エラーは発生しない。 @fragment fn frag2 () { }
8.2. 不定値
限定された場合には、ランタイム式の評価が、 その部分式に対してサポートされていない値を使用して行われることがある。
そのような場合、その評価結果は式の静的型の不定値となる。 これは、静的型に属する、実装が任意に選択した何らかの値を意味する。
式が評価される一意な動的コンテキストごとに、異なる値が生成されることがある。 たとえば、ループの反復ごとに 1 回評価される場合、 ループの反復ごとに異なる値が計算されることがある。
注: 型が浮動小数点型であり、 実装が 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])、または -
スウィズル名を使用する。 これは、ソースベクトルの成分へそれぞれ対応する簡略名の並びとして記述される コンテキスト依存名である。
-
色を表す簡略名の集合:ベクトル成分 0、1、2、3 にそれぞれ対応する
r、g、b、a。 -
次元を表す簡略名の集合:ベクトル成分 0、1、2、3 にそれぞれ対応する
x、y、z、w。
-
簡略名には . 表記を使用してアクセスする(たとえば、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 成分を選択する
これは 1 文字のスウィズルである。 |
| e: vecN<T> |
e.y: Te .g: T
|
eの第 2 成分を選択する
これは 1 文字のスウィズルである。 |
| e: vecN<T> Nは 3 または 4 |
e.z: Te .b: T
|
eの第 3 成分を選択する
これは 1 文字のスウィズルである。 |
| e: vec4<T> |
e.w: Te .a: T
|
eの第 4 成分を選択する
これは 1 文字のスウィズルである。 |
| e: vecN<T> i: i32 または u32 Tは具象 | e[i]: T |
ベクトルの第 i 成分を選択する 最初の成分はインデックス i=0 にある。 iが範囲 [0,N-1] の外側にある場合:
|
| e: vecN<T> i: i32 または u32 Tは抽象 iはconst 式 | e[i]: T |
ベクトルの第 i 成分を選択する 最初の成分はインデックス i=0 にある。 iが範囲 [0,N-1] の外側にある場合、 シェーダー作成エラーとなる。 注: 抽象ベクトル値 eに、const 式ではない式を使用してインデックス付けする場合、 インデックスを適用する前にベクトルが具象化される。 |
8.5.1.2. ベクトルの複数成分の選択
この節の式は、内側の式に複数文字のスウィズルを適用する:
-
内側の式がベクトルである場合、 結果はベクトルとなる。以下の表を参照のこと。
-
内側の式が、ベクトルの格納型を持つポインターまたは参照である場合:
-
swizzle_assignment言語 拡張がサポートされていない場合、 結果はベクトルとなる。以下の表を参照のこと。
-
swizzle_assignment言語 拡張がサポートされている場合は、 代わりに§ 8.6 スウィズルビュー式を参照のこと。
-
注: swizzle_assignment言語拡張がサポートされていない 場合、複数文字のスウィズルを 代入の左辺に置くことはできない。 代入の左辺は参照型でなければならないが、 この拡張がない場合、複数文字のスウィズル式は常にベクトル型の値を生成するためである。
| 前提条件 | 結論 | 説明 |
|---|---|---|
|
e: vecN<T> Iは文字 x、y、z、または wJは文字 x、y、z、または w |
e.IJ: vec2<T> | 第 1 成分が e.I、第 2 成分が
e.Jである 2 成分ベクトルを計算する。 文字 z は、Nが 3 または 4 の場合にのみ有効である。文字 w は、Nが 4 の場合にのみ有効である。 |
|
e: vecN<T> Iは文字 r、g、b、または aJは文字 r、g、b、または a |
e.IJ: vec2<T> | 第 1 成分が e.I、第 2 成分が
e.Jである 2 成分ベクトルを計算する。 文字 b は、Nが 3 または 4 の場合にのみ有効である。文字 a は、Nが 4 の場合にのみ有効である。 |
|
e: vecN<T> Iは文字 x、y、z、または wJは文字 x、y、z、または wKは文字 x、y、z、または w |
e.IJK: vec3<T> | 第 1 成分が e.I、第 2 成分が
e.J、第 3 成分が e.Kである
3 成分ベクトルを計算する。 文字 z は、Nが 3 または 4 の場合にのみ有効である。文字 w は、Nが 4 の場合にのみ有効である。 |
|
e: vecN<T> Iは文字 r、g、b、または aJは文字 r、g、b、または aKは文字 r、g、b、または a |
e.IJK: vec3<T> | 第 1 成分が e.I、第 2 成分が
e.J、第 3 成分が e.Kである
3 成分ベクトルを計算する。 文字 b は、Nが 3 または 4 の場合にのみ有効である。文字 a は、Nが 4 の場合にのみ有効である。 |
|
e: vecN<T> Iは文字 x、y、z、または wJは文字 x、y、z、または wKは文字 x、y、z、または wLは文字 x、y、z、または w |
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: vecN<T> Iは文字 r、g、b、または aJは文字 r、g、b、または aKは文字 r、g、b、または aLは文字 r、g、b、または a |
e.IJKL:
vec4<T> | 第 1 成分が e.I、第 2 成分が
e.J、第 3 成分が e.K、第 4 成分が
e.Lである 4 成分ベクトルを計算する。 文字 b は、Nが 3 または 4 の場合にのみ有効である。文字 a は、Nが 4 の場合にのみ有効である。 |
| 前提条件 | 結論 | 説明 |
|---|---|---|
|
swizzle_assignmentはサポートされていない
pr: ref<AS,vecN<T,AM>> または
ptr<AS,vecN<T,AM>> |
pr.IJ: vec2<T> |
eを、評価時に pr が参照するメモリ位置に格納されている
ベクトルとして、e.IJを計算する。
文字 |
|
swizzle_assignmentはサポートされていない
pr: ref<AS,vecN<T,AM>> または
ptr<AS,vecN<T,AM>> |
pr.IJ: vec2<T> |
eを、評価時に pr が参照するメモリ位置に格納されている
ベクトルとして、e.IJを計算する。
文字 |
|
swizzle_assignmentはサポートされていない
pr: ref<AS,vecN<T,AM>> または
ptr<AS,vecN<T,AM>> |
pr.IJK: vec3<T> |
eを、評価時に pr が参照するメモリ位置に格納されているベクトルとして、
e.IJKを計算する。
文字 |
|
swizzle_assignmentはサポートされていない
pr: ref<AS,vecN<T,AM>> または
ptr<AS,vecN<T,AM>> |
pr.IJK: vec3<T> |
eを、評価時に pr が参照するメモリ位置に格納されているベクトルとして、
e.IJKを計算する。
文字 |
|
swizzle_assignmentはサポートされていない
pr: ref<AS,vecN<T,AM>> または
ptr<AS,vecN<T,AM>> |
pr.IJKL:
vec4<T> |
eを、評価時に pr が参照するメモリ位置に格納されているベクトルとして、
e.IJKLを計算する。
文字 |
|
swizzle_assignmentはサポートされていない
pr: ref<AS,vecN<T,AM>> または
ptr<AS,vecN<T,AM>> |
pr.IJKL:
vec4<T> |
eを、評価時に pr が参照するメモリ位置に格納されているベクトルとして、
e.IJKLを計算する。
文字 |
8.5.1.3. ベクトルメモリビューまたは スウィズルビューからの成分参照
この節の式は、ベクトル全体のメモリビューまたはスウィズルビューから、メモリ内の ベクトルの単一成分への 参照を形成する。
WGSL の型規則により、 このような式は次の場所に現れることができる:
-
メモリ内のその成分へ書き込むための代入の左辺、または
-
ベクトル成分への参照を置くことができる任意の場所。 読み込み規則が適用される場合があるため、 これにはスカラー値を置くことができる任意の場所が含まれる。
ベクトルの成分への書き込みアクセスは、そのベクトルに関連付けられたすべての メモリ位置へアクセスすることがある。
注: これは、異なる呼び出しがメモリ内の ベクトルの異なる成分へアクセスする場合、少なくとも 1 つが書き込みアクセスであれば、 それらのアクセスを同期しなければならないことを意味する。 § 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の起点変数と同じである。 |
| 前提条件 | 結論 | 説明 |
|---|---|---|
|
sv : swizzle<AS,S,N,K> |
sv.x : ref<AS,S,read_write>sv. r : ref<AS,S,read_write>
|
svをスウィズルビュー(p、
« Idx0,...,IdxK−1 »)とする。
結果は、ポインター p のメモリビュー内にある インデックス Idx0 の成分への参照である。 結果の参照の起点変数は、 svの起点変数と同じである。 |
|
sv : swizzle<AS,S,N,K> |
sv.y : ref<AS,S,read_write>sv. g : ref<AS,S,read_write>
|
svをスウィズルビュー(p、
« Idx0,...,IdxK−1 »)とする。
結果は、ポインター p のメモリビュー内にある インデックス Idx1 の成分への参照である。 結果の参照の起点変数は、 svの起点変数と同じである。 |
|
sv : swizzle<AS,S,N,K> ここで K ≥ 3 |
sv.z : ref<AS,S,read_write>sv. b : ref<AS,S,read_write>
|
svをスウィズルビュー(p、
« Idx0,...,IdxK−1 »)とする。
結果は、ポインター p のメモリビュー内にある インデックス Idx2 の成分への参照である。 結果の参照の起点変数は、 svの起点変数と同じである。 |
|
sv : swizzle<AS,S,N,K> ここで K = 4 |
sv.w : ref<AS,S,read_write>sv. a : ref<AS,S,read_write>
|
svをスウィズルビュー(p、
« Idx0,...,IdxK−1 »)とする。
結果は、ポインター p のメモリビュー内にある インデックス Idx3 の成分への参照である。 結果の参照の起点変数は、 svの起点変数と同じである。 |
|
sv : swizzle<AS,S,N,K> i : i32 または u32 |
sv[i] : ref<AS,S,read_write> |
svをスウィズルビュー(p、
« Idx0,...,IdxK−1 »)とする。
iが [0, K) 内にある場合、式は次の参照となる (*p)[ Idxi ] 注: svが 無効なスウィズルビューである場合、 結果は無効なメモリ参照となる。 iが [0,K) の外側にある場合:
結果の参照の起点変数は、 svの起点変数と同じである。 |
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が符号付き整数であり、iが 0 より小さい場合:
結果の参照の起点変数は、 rの起点変数と同じである。 |
8.5.4. 構造体アクセス式
| 前提条件 | 結論 | 説明 |
|---|---|---|
|
Sは構造体型 Mは、型 T を持つ S のメンバーの識別子名 e: S | e.M: T | 結果は、構造体値 e に含まれる 名前 M のメンバーの値となる。 |
| 前提条件 | 結論 | 説明 |
|---|---|---|
|
Sは構造体型 Mは、型 T を持つ S のメンバーの識別子名 r: ref<AS,S,AM> または ptr<AS,S,AM> | r.M: ref<AS,T,AM> | 構造体へのメモリビューが与えられた場合、結果は識別子名 M を持つ
構造体メンバーへの参照となる。 結果の参照の起点変数は、 rの起点変数と同じである。 |
8.6. スウィズルビュー式
スウィズルビュー式は、swizzle_assignment言語拡張によって有効になる。
スウィズルビューは、 次の方法で形成される:
これらの規則により、スウィズルビューのインデックスリスト部分は、 シェーダー作成時に完全に決定される。
この節では、スウィズルインデックス関数 SI を次のように定義する:
-
SI(
x) = 0 -
SI(
y) = 1 -
SI(
z) = 2 -
SI(
w) = 3 -
SI(
r) = 0 -
SI(
g) = 1 -
SI(
b) = 2 -
SI(
a) = 3
次の場合、スウィズル名 Z は K 個のインデックス « Idx0, ..., IdxK−1 » を表すという:
-
次のいずれかが真である:
-
Z内の各文字が
x、y、z、またはwである、または -
Z内の各文字が
r、g、b、またはaである
-
-
各 Idxi が SI(L) に等しい。ここで Lは Z 内の第 i 文字である。
注: たとえば、スウィズル wzyx は
4 つのインデックス «3, 2, 1, 0» を表し、スウィズル rb は 2 つのインデックス «0, 2» を表す。
スウィズル rgbz は rgba の文字と
xyzwの文字を混在させているため、いかなるインデックス列も表さない。
| 前提条件 | 結論 | 説明 |
|---|---|---|
|
swizzle_assignmentがサポートされている
r: ref<AS,T,read_write> | r.Z : swizzle<AS,S,N,K> |
結果はスウィズル
ビュー(&r, I)となる。
I内の各インデックスは N より小さくなければならない。 rが無効なメモリ参照である場合、結果は 無効なスウィズルビューとなる。 |
| 前提条件 | 結論 | 説明 |
|---|---|---|
|
swizzle_assignmentがサポートされている pointer_composite_accessが サポートされている p: ptr<AS,T,read_write> | p.Z : swizzle<AS,S,N,K> |
結果はスウィズル
ビュー(p, I)となる
I内の各インデックスは N より小さくなければならない。 pが無効なポインターである場合、結果は無効なスウィズルビューとなる。 |
| 前提条件 | 結論 | 説明 |
|---|---|---|
|
sv: swizzle<AS,S,N,Kin> スウィズル名 Z は KZ 個のインデックス IZ = « IZ [0], ..., IZ [KZ −1] » を表す KZは {2,3,4} に含まれる | sv.Z : swizzle< AS,S,N,KZ > |
svをスウィズルビュー(p, Iin)とする。
定義により、列 Iin は Kin 個の項目を持つ。
Ioutを次の列とする: 式の結果は、スウィズルビュー(p, Iout)となる。 IZ内の各インデックスは、 Kinより小さくなければならない。 svが無効なスウィズルビューである場合、結果は無効なスウィズルビューとなる。 |
8.7. 論理式
| 前提条件 | 結論 | 説明 |
|---|---|---|
| e: T Tは bool または vecN<bool> | !e: T
| 論理否定。
eが false の場合、結果は true となり、
eが true の場合、結果は false となる。
Tがベクトルの場合は成分ごと。
|
| 前提条件 | 結論 | 説明 |
|---|---|---|
| e1: bool e2: bool | e1 || e2: bool
| 短絡「または」。e1または e2 のいずれかが
true の場合、trueを生成する。
e1が false の場合にのみ e2 を評価する。
|
| e1: bool e2: bool | e1 && e2: bool
| 短絡「かつ」。e1と e2 の両方が
true の場合、trueを生成する。
e1が true の場合にのみ e2 を評価する。
|
| e1: T e2: T Tは bool または vecN<bool> | e1 | e2: T
| 論理「または」。Tがベクトルの場合は成分ごと。 e1と e2 の両方を評価する。 |
| e1: T e2: T Tは bool または vecN<bool> | e1 & e2: T
| 論理「かつ」。Tがベクトルの場合は成分ごと。 e1と e2 の両方を評価する。 |
8.8. 算術式
| 前提条件 | 結論 | 説明 |
|---|---|---|
| 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が浮動小数点型の場合、結果は次と等しい: 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.9. 比較式
| 前提条件 | 結論 | 説明 |
|---|---|---|
| e1: T e2: T S は AbstractInt、AbstractFloat、bool、i32、u32、f32、または f16 T は S または vecN<S> T がベクトルの場合、TB は vecN<bool>、 それ以外の場合、TB は bool | e1 == e2: TB
| 等価。T がベクトルの場合、成分ごと。 |
| e1: T e2: T S は AbstractInt、AbstractFloat、bool、i32、u32、f32、または f16 T は S または vecN<S> T がベクトルの場合、TB は vecN<bool>、 それ以外の場合、TB は bool | e1 != e2: TB
| 非等価。T がベクトルの場合、成分ごと。 |
| e1: T e2: T S は AbstractInt、AbstractFloat、 i32、u32、f32、または f16 T は S、または vecN<S> T がベクトルの場合、TB は vecN<bool>、 それ以外の場合、TB は bool | e1 < e2: TB
| 未満。T がベクトルの場合、成分ごと。 |
| e1: T e2: T S は AbstractInt、AbstractFloat、 i32、u32、f32、または f16 T は S、または vecN<S> T がベクトルの場合、TB は vecN<bool>、 それ以外の場合、TB は bool | e1 <= e2: TB
| 以下。T がベクトルの場合、成分ごと。 |
| e1: T e2: T S は AbstractInt、AbstractFloat、 i32、u32、f32、または f16 T は S、または vecN<S> T がベクトルの場合、TB は vecN<bool>、 それ以外の場合、TB は bool | e1 > e2: TB
| より大きい。T がベクトルの場合、成分ごと。 |
| e1: T e2: T S は AbstractInt、AbstractFloat、 i32、u32、f32、または f16 T は S、または vecN<S> T がベクトルの場合、TB は vecN<bool>、 それ以外の場合、TB は bool | e1 >= e2: TB
| 以上。T がベクトルの場合、成分ごと。 |
8.10. ビット式
| 前提条件 | 結論 | 説明 |
|---|---|---|
| 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> T が S の場合、TS は u32。それ以外の場合、TS は vecN<u32> | e1 << e2: T
|
左シフト(シフトされる値は具象):
e1 を左にシフトし、最下位位置にゼロビットを挿入し、 最上位ビットを破棄する。 シフトするビット数は、e2 の値を
e1 のビット幅で剰余を取った値である。
e1 と e2 の両方がシェーダー実行開始前に 判明している場合、結果はオーバーフローしてはならない:
T がベクトルの場合、成分ごと。 |
| e1: T e2: TS T は AbstractInt または vecN<AbstractInt> T が AbstractInt の場合、TS は u32。それ以外の場合、TS は vecN<u32> | e1 << e2: T
|
左シフト(シフトされる値は抽象):
e1 を左にシフトし、最下位位置にゼロビットを挿入し、 最上位ビットを破棄する。 シフトするビット数は e2 の値である。 e1 の最上位 e2+1 ビットは、同じ ビット値でなければならない。 そうでなければオーバーフローが発生する。 注: この条件は、破棄されるすべての ビットが元の値の符号ビットと同じであり、 かつ最終的な値の符号ビットとも同じでなければならないことを意味する。 T がベクトルの場合、成分ごと。 |
| e1: T e2: TS S は i32 または u32 T は S または vecN<S> T が S の場合、TS は u32。それ以外の場合、TS は vecN<u32> | e1 >> e2: T |
右シフト(シフトされる値は具象)。
e1 を右にシフトし、最下位ビットを破棄する。 S が符号なし型の場合、最上位位置にゼロビットを挿入する。 S が符号付き型の場合:
シフトするビット数は、e2 の値を e1 のビット幅で 剰余を取った値である。 e2 が e1 のビット幅以上の場合、次のようになる:
T がベクトルの場合、成分ごと。 |
| e1: T e2: TS T は AbstractInt または vecN<AbstractInt> T が AbstractInt の場合、TS は u32。それ以外の場合、TS は vecN<u32> | e1 >> e2: T |
右シフト(抽象)。
e1 を右にシフトし、最下位ビットを破棄する。 e1 が負の場合、挿入される各ビットは 1 となり、そのため結果も負になる。 それ以外の場合、挿入される各ビットは 0 となる。 シフトするビット数は e2 の値である。 T がベクトルの場合、成分ごと。 |
8.11. 関数呼び出し式
関数呼び出し式は、呼び出される関数が戻り値の型を持つ関数呼び出しを実行する。 呼び出される関数が値を返さない場合は、代わりに関数呼び出し文を 使用すべきである。 § 9.5 関数呼び出し文を参照。
8.12. 変数識別子式
| 前提条件 | 結論 | 説明 |
|---|---|---|
| v は、アドレス空間 AS で宣言され、 格納型 T およびアクセスモード AM を持つ、 スコープ内の変数へ 解決される 識別子 | v: ref<AS,T,AM> | 結果は、名前付き変数 v のメモリへの参照となる。 |
8.13. 仮引数式
| 前提条件 | 結論 | 説明 |
|---|---|---|
| a は、型 T を持つ スコープ内の仮引数 宣言へ解決される識別子 | a: T | 結果は、この関数のインスタンスを呼び出している呼び出し箇所で、 対応する関数呼び出しオペランドに指定された値となる。 |
8.14. アドレス取得式
アドレス取得演算子は、 参照を対応するポインターへ変換する。
| 前提条件 | 結論 | 説明 |
|---|---|---|
| r: ref<AS,T,AM> |
&r: ptr<AS,T,AM>
|
結果は、参照値 r と同じメモリビューに対応する
ポインター値となる。
r が無効なメモリ参照の場合、結果の ポインターも無効なメモリ参照となる。 AS が handle アドレス空間の場合、 シェーダー作成エラーとなる。 r が ベクトル成分への参照の場合、 シェーダー作成エラーとなる。 |
8.15. 間接参照式
間接参照演算子は、 ポインターを対応する参照へ変換する。
| 前提条件 | 結論 | 説明 |
|---|---|---|
| p: ptr<AS,T,AM> |
*p: ref<AS,T,AM>
|
結果は、ポインター値 p と同じメモリビューに対応する
参照値となる。
p が無効なメモリ参照の場合、結果の 参照も無効なメモリ参照となる。 |
8.16. 値宣言に対する識別子式
| 前提条件 | 結論 | 説明 |
|---|---|---|
| c は、型 T を持つ スコープ内の const 宣言へ 解決される識別子 | c: T | 結果は初期化式について計算された値となる。 この式は const 式であり、シェーダー作成時に評価される。 |
| c は、型 T を持つ スコープ内の override 宣言へ 解決される識別子 | c: T |
パイプライン作成時に定数 IDの値が
指定されていた場合、結果はその値となる。
この値は、パイプラインインスタンスごとに異なることがある。
それ以外の場合、結果は初期化式について計算された値となる。 パイプラインでオーバーライド可能な定数はモジュールスコープに現れるため、評価は シェーダーが実行を開始する前に行われる。 注: API 呼び出しで
初期値が指定されておらず、
かつ |
| c は、型 T を持つ スコープ内の let 宣言へ 解決される識別子 | c: T | 結果は初期化式について計算された値となる。
let
宣言は関数本体内に現れ、その初期化子は、
制御フローが宣言に到達するたびに
評価される。 |
8.17. 列挙式
| 前提条件 | 結論 | 説明 |
|---|---|---|
| e は、列挙型 E に属する、 事前宣言された列挙子へ 解決される識別子 (列挙型) | e : E | § 6.4.1 事前宣言された列挙子を参照 |
8.18. 型式
| 前提条件 | 結論 | 説明 |
|---|---|---|
| t は、事前宣言された型へ 解決される識別子 | t : AllTypes | § 6.10 事前宣言された型と型ジェネレーターの概要を参照 |
| a は、型エイリアスへ 解決される識別子。 | a : AllTypes | さらに、a はエイリアス先の型を表す。 |
| s は、構造体型の宣言へ 解決される識別子。 | s : AllTypes | さらに、s は構造体型を表す。 |
|
tg は、型ジェネレーターへ
解決される識別子
e1: T1 | tg _template_args_start e1, ..., eN _template_args_end : AllTypes |
各型ジェネレーターは、必要とし受け入れるテンプレート
パラメーターについて固有の要件を持ち、
テンプレートパラメーターが結果の型の決定にどのように寄与するかを定義する。
式 e1 から eN は、その型ジェネレーターの テンプレートパラメーター である。 たとえば、型式 事前宣言された型ジェネレーターの一覧については、 § 6.10 事前宣言された型と型ジェネレーターの概要を参照。 注: ここにある 2 つの変種の違いは、 eN の後に末尾のコンマがあるかどうかだけである。 |
| tg _template_args_start e1, ..., eN, _template_args_end : AllTypes |
8.19. 式の文法の概要
識別子が 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.20. 演算子の優先順位と結合規則
この小節全体は参考情報である。
WGSL の右辺式における演算子の優先順位と結合規則は、 要約すると、その文法から生じる。右辺式では、次の図に示すように、 演算子をまとめて構成する:
冗長な記述によって可読性を高めるため、次のグループは他のグループとは結合しない:
また、次のグループは自身とは結合しない:
上記 2 つのグループ区分をまたいで結合するには、関係を明示的に設定する括弧が必要となる。 次の例では、これらの規則によって式が無効になる箇所をコメントで示す:
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)) が推定される。
次の表は、演算子の優先順位、結合規則、および結合対象を、最も強いものから 最も弱いものの順にまとめたものである。結合対象の列には、指定された演算子より強い式が 記載される。たとえば、値が「上記すべて」である場合、この演算子には より強い任意の式を含めることができる。一方、たとえば値が「単項」である場合、 単項式より弱く、その行の演算子より強いものをこの演算子と結合するには 括弧が必要となる。この列は、演算子を線形に列挙するために必要である。
| 名前 | 演算子 | 結合規則 | 結合対象 |
|---|---|---|---|
| 括弧付き | (...)
| ||
| 基本 | 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.5.9 参照値とポインター値の形成を参照。
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. スウィズル代入
この節は、swizzle_assignment言語拡張が サポートされている場合にのみ適用される。
代入は、
左辺が
スウィズルビューであり、
演算子が等号('=')トークンであるとき、
スウィズル代入である。
この場合、右辺の値を更新ベクトルとして使用し、
左辺に対するスウィズルビュー書き込みが実行される。
| 前提条件 | 文 | 説明 |
|---|---|---|
|
sv : swizzle<AS,S,N,K> e : vecK<S> アドレス空間 ASは書き込み可能、 | sv = e |
規約により、sv = (p, IndexList)
制約:
注: スウィズルビュー式の規則により、 IndexList内の各インデックスが [0,N-1] に含まれることが保証される。 次の手順を実行する。
注: スウィズルビューが 無効なスウィズルビューである場合、 手順 3 と 4 は範囲外アクセスとなるため、 実行されないか、想定とは異なるメモリ位置へ書き込まれることがある。 注: pの古い内容を読み取る前にeを評価するのは、 不自然に思えるかもしれない。 しかし、手順 4 のスウィズル書き込みでは、IndexListに列挙されて いないベクトル成分を維持しなければならず、 それらの成分はe自体の評価中に変更されている可能性がある。 |
var < private> v : array< vec4u, 1 > ; fn update_and_index () -> u32{ v [ 0 ] += vec4u( 2 , 4 , 8 , 10 ); return 0 ; } fn update_and_rhs () -> vec2u{ v [ 0 ]. x = 900 ; v [ 0 ]. z = 100 ; return vec2u( 55 , 66 ); } fn eval_order_swizzle_assignment () { v [ 0 ] = vec4u( 0 , 0 , 0 , 0 ); // 1. ポインター p を評価する。これにより左辺の // インデックスが評価され、副作用として // v[0] = vec4u(2,4,8,10) が設定され、 // インデックスとして 0 が得られる。 // 2. 右辺を評価し、 // v[0].x = 900 // v[0].z = 100 // を設定して vec2u(55,66) を得る。 // 3. その後、スウィズル代入は v[0].x と v[0].y のみを更新し、 // v[0].z と v[0].w を維持する。 v [ update_and_index ()]. yx = update_and_rhs (); // この時点で v[0] は vec4u(66,55,100,10) に等しい。 }
9.2.3. ダミー代入
代入は、
左辺が
アンダースコア('_')トークンであるとき、
ダミー代入である。
この場合、右辺は
評価された後、無視される。
| 前提条件 | 文 | 説明 |
|---|---|---|
| e: T, Tは構築可能、ポインター型、 テクスチャ型、または サンプラー型 | _ = e |
eを評価する。
注: 結果の値は格納されない。
|
ダミー代入は次の場合に有用である:
-
値を返す関数を呼び出しつつ、結果の値が不要であることを明確に表す場合。
-
変数へ静的にアクセスし、 その変数をシェーダーのリソースインターフェースの 一部として確立する場合。
注: バッファー変数の格納型は、 たとえばアトミック型またはランタイムサイズ配列を含む場合、構築可能でないことがある。 その場合は、代わりに変数の内容へのポインターを使用する。
var < private> counter : i32; fn increment_and_yield_previous () -> i32{ let previous = counter ; counter = counter + 1 ; return previous ; } fn user () { // カウンターをインクリメントするが、結果は使用しない。 _ = 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.4. 複合代入
代入は、 左辺が 参照式または スウィズルビューであり、 演算子がcompound_assignment_operatorsの いずれかであるとき、複合代入である。
各文の型要件、意味論、および動作は、次の例外を除き、 次の表のとおり複合代入を展開したものとして定義される:
-
式e1が参照式である場合:
-
e1の参照型は、 read_write アクセスモードを持た なければならない。
-
次の手順を実行する。
-
&e1を評価し、ポインターpを得る。
-
pによって参照されるメモリを読み取り、 値old_contentsを得る。
次に示す展開では、old_contentsを e1の値として使用する。
-
e2を評価する。
-
old_contentsとe2に対して指定された二項演算を実行し、 updateを計算する。
-
たとえば、複合代入が
v += wである場合、 指定される演算は加算である。
-
-
ポインターpを介して、updateをメモリへ書き込む。
-
-
-
式e1がスウィズルビュー式である場合:
-
規約により、スウィズルビューe1は (p, IndexList) と表記できる。
-
注: pの型は read_write アクセスモードを持つ。
-
-
スウィズル代入と同じ制約が適用される:
-
IndexList内のインデックスは、すべて互いに異なら なければならない。
-
注: スウィズルビュー式の規則により、 IndexList内の各インデックスが [0,N-1] に含まれることが保証される。
-
-
次の手順を実行する。
-
pを評価する。
-
SwizzleViewRead(p, IndexList)を実行し、 型 vecK<S> のベクトル viewed_contentsを得る。
これは、次に示す展開の二項演算子の左オペランドとして使用される場合の、 e1の値である。 二項式が左から右へ評価されることを保証するため、 これはe2の評価より前に行わなければならない。
-
e2を評価する。
-
pによって参照されるメモリを読み取り、 型 vecN<S> のベクトルold_contentsを得る。
-
viewed_contentsとe2に対して指定された二項演算を実行し、 updateを計算する。
-
たとえば、スウィズル代入が
v.xy += wである場合、 指定される演算は加算である。
-
-
SwizzleViewWrite(p, IndexList, old_contents, update)を実行する。
-
-
| 文 | 展開 |
|---|---|
| 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が 参照である場合、評価は 1 回だけ行われるが、 その基礎となるメモリには 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 ; // advance_item() を 1 回だけ呼び出し、data[0] に 5.0 を加算する。 data [ advance_item ()] += 5.0 ; // ここで next_item は 1 になる。 } fn precedence_example () { var value = 1 ; // 複合代入の右辺は、それ自体が 1 つの式である。 value *= 2 + 3 ; // value = value * (2 + 3); と同じ // 'value' は現在 5 を保持している。 }
var < private> v : array< vec4u, 1 > ; fn update_and_index () -> u32{ v [ 0 ] += vec4u( 2 , 4 , 8 , 10 ); return 0 ; } fn update_and_rhs () -> vec2u{ v [ 0 ]. x = 900 ; v [ 0 ]. z = 100 ; return vec2u( 55 , 66 ); } fn eval_order_compound_swizzle_assignment () { v [ 0 ] = vec4u( 0 , 0 , 0 , 0 ); // 1. ポインター p を評価する。これにより左辺の // インデックスが評価され、副作用として // v[0] = vec4u(2,4,8,10) が設定され、 // インデックスとして 0 が得られる。 // 2. スウィズル名は .yx であるため、IndexList はリスト 1,0 となる。 // SwizzleViewRead(p,IndexList) を実行し、 // view_contents = vec2u(4,2) を得る。 // 3. 右辺を評価し、 // v[0].x = 900 // v[0].z = 100 // を設定して vec2u(55,66) を得る。 // 4. 次のように更新ベクトルを計算する。 // view_contents + vec2u(55,66) // = vec2u(4,2) + vec2u(55,66) // = vec2u(59,68) // 5. その後、スウィズル代入は v[0].x と v[0].y のみを更新し、 // v[0].z と v[0].w を維持する。 v [ update_and_index ()]. yx += update_and_rhs (); // この時点で v[0] は vec4u(68,59,100,10) に等しい。 }
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) と同じ |
fn f () { var a : i32= 20 ; a ++ ; // この時点で a には 21 が格納されている a -- ; // この時点で a には 20 が格納されている }
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 文には、default 節がちょうど 1 つ なければならない。
'default'トークンは、
1 つのcase_selectorリスト内に複数回現れては
ならない。
型規則の前提条件: 1 つの switch 文について、セレクター式とすべての case セレクター式は、 同じ具象な整数スカラー型で なければならない。
case_selectors内の式は、 const 式で なければならない。
同じ switch 文内の異なる 2 つの case セレクター式が、 同じ値を持ってはならない。
セレクター値がcase_selectorリスト内の式の値と等しい場合、 制御はそのcase 節の本体へ移る。 セレクター値がいずれの case セレクター値とも等しくない場合、 制御はdefault 節の本体へ移る。
制御が節の本体の末尾へ到達すると、switch 文の直後にある最初の文へ移る。
節の本体内にある文の 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 セレクターでは const 式を使用できる a = 3 ; } case 3 , default { // default キーワードは他の節とともに使用できる a = 4 ; } }
9.4.3. Loop 文
loop文は、ループ本体を繰り返し実行する。 ループ本体は複文として指定される。 ループ本体の各実行を反復と呼ぶ。
この繰り返しは、break文または return文によって 中断できる。
必要に応じて、ループ本体の最後の文を continuing文にできる。
loopが 無制限の回数の反復を実行することになる場合、 動的エラーが発生する。 これにより、ループの早期終了、その他の非局所的な影響、さらには デバイス喪失が生じることもある。
ループ本体内の文の 1 つが宣言である場合、 その宣言は、複文内の宣言についての通常の スコープおよび 生存期間の規則に従う。 つまり、ループ本体は文の列であり、そのいずれかが宣言である場合、 その宣言のスコープは、列内の次の文の先頭からループ本体の末尾まで広がる。 宣言は到達するたびに実行されるため、新しい反復ごとに 変数または値の新しいインスタンスが作成され、 再初期化される。
注: loop 文は特殊な構文であるため、
通常はfor文またはwhile文を使用する。
loop 文は、他のシェーダー言語との最も大きな相違点の 1 つである。
この設計は、コンパイル済みコードで一般的に見られるループの慣用形を直接表現する。 特に、ループの更新文をループ本体の末尾に配置することで、 ループ本体で定義された値を自然に使用できる。
-
<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文は、loop文を含む複文に対する構文糖である。
一般に、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型の式で なければならない。
-
条件が存在する場合、for ループ本体を実行する直前に評価される。 条件が false の場合、§ 9.4.6 Break 文が実行され、 ループの実行が終了する。 この検査は各ループ反復の先頭で行われる。
-
-
update_partが空でない場合、それはループ構文の末尾にある continuing文となる。 -
脱糖では、
update_part内のすべての識別子が、 脱糖前と同じ宣言へ引き続き解決されることを保証するため、 必要に応じてbody内で宣言された識別子の名前を変更 する。
for ループのinitializerは、ループの実行前に 1 回実行される。
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文は、条件によってパラメーター化されたループの一種である。 ループの各反復の先頭で、ブール条件が評価される。 条件が false の場合、while ループの実行は終了する。 それ以外の場合、反復の残りの部分が実行される。
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文の本体の直後へ移り、 そのループの実行を終了する。
注: 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文は、最も近くで囲んでいる loop内で制御を次のように移す:
-
そのループの本体の末尾にcontinuing文が存在する場合は、 そこへ前方に移す。
-
存在しない場合は、ループ本体の最初の文へ後方に移し、 次の反復を開始する。
continue文は、loop文、for文、または
while文内でのみ
使用しなければならない。
continue文は、囲んでいるcontinuing文へ
制御を移すことになる位置に配置してはならない。
(continuing文へ分岐する場合は、前方分岐となる。)
continue文は、対象のcontinuing文で
使用される宣言を飛び越えて制御を移すことになる位置に配置しては
ならない。
注:
continueをcontinuing文内で使用できるのは、
そのcontinuing文内に入れ子になった別のループ内で
制御フローを移すために使用する場合のみである。
つまり、現在実行中のcontinuing文の先頭へ制御を移すために
continueを使用することはできない。
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 に // 設定されることはない。 discard ; } will_emit_color = 1 ; } @fragment fn main ( @builtin ( position) coord_in : vec4< f32> ) -> @location ( 0 ) vec4< f32> { discard_if_shallow ( coord_in ); // 値を 1 に設定して赤色を出力するが、それはヘルパー関数が // discard 文を実行しなかった場合に限られる。 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 一様性を参照)が認識する必要がある。
これらの目的は、文の実行動作を要約する仕組みによって達成される。 動作解析は、各文を、その文の評価完了後に実行が進む可能性のある方法の集合へ対応付ける。 値と式の型解析と同様に、動作解析はボトムアップで進める。 最初に特定の基本的な文の動作を決定し、次に結合規則を適用して より高水準の構文の動作を決定する。
動作とは、要素が次のいずれかとなる集合である:
-
Return
-
Break
-
Continue
-
Next
これらはそれぞれ、キーワードによるか、次の文へそのまま進む (「Next」)ことによって複文を抜ける方法に対応する。
sが動作に関する規則を満たし、 動作Bを持つことを、 「s: B」と表記する。
各関数について:
-
その本体は、これらの規則に従った有効な文で なければならない。
各関数に動作を割り当てる。 それは、その本体を通常の文として扱った場合の 動作において、 「Return」を「Next」で置き換えたものである。 上記の規則の結果として、関数の動作は常に {} または {Next} のいずれかとなる。
動作解析は、各文および各関数について、 空でない動作を決定でき なければならない。
| 文 | 前提条件 | 結果の動作 |
|---|---|---|
| 空文 | {Next} | |
| {s} | s: B | B |
|
s1 s2
注: s1は多くの場合、セミコロンで終わる。 | s1: B1 Next はB1に含まれる s2: B2 | (B1∖{Next}) ∪ B2 |
| s1: B1 Next はB1に含まれない 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} {Continue, Return} のいずれもB2に含まれない | {Return} |
|
s1: B1 s2: B2 B1 ≠ {Return} {Continue, Return} のいずれもB2に含まれない Break は (B1 ∪ B2) に含まれない | (B1 ∪ B2)∖{Continue, Next} | |
|
s1: B1 s2: B2 B1 ≠ {Return} {Continue, Return} のいずれもB2に含まれない Break は (B1 ∪ B2) に含まれる | (B1 ∪ B2 ∪ {Next})∖{Break, Continue} | |
| switch e {case c1: s1 ... case cn: sn} |
s1: B1 ... sn: Bn Break は (B1 ∪ ... ∪ Bn) に含まれない | B1 ∪ ... ∪ Bn |
|
s1: B1 ... sn: Bn Break は (B1 ∪ ... ∪ Bn) に含まれる | (B1 ∪ ... ∪ Bn ∪ {Next})∖Break |
注: ∪ は集合の和演算、∖ は集合の差演算である。
注: 空文の場合は、
loopの本体が空である場合、またはforループに
初期化文または更新文がない場合に生じる。
この解析では:
-
forループは脱糖される (§ 9.4.4 For 文を参照)。 -
whileループは脱糖される (§ 9.4.5 While 文を参照)。 -
loop {s}はloop {s continuing {}}として扱われる。 -
else分岐のないif文は、 空の else 分岐を持つ、すなわちelse {}で終わるものとして扱われる。 これにより、その動作に Next が追加される。 -
else if分岐を持つif文は、 入れ子になった単純なif/else文として扱われる。 -
defaultで始まるswitch_clauseは、case _:で始まるswitch_clauseと同様に動作する。
各組み込み関数は、 {Next} という動作を持つ。 また、上の表に記載されていない各演算子の適用は、 同じオペランドを持ち、関数の動作が {Next} である 関数呼び出しと同じ動作を持つ。
関数の動作は、上記の規則を満たさ なければならない。
注: 上記の規則から、 ループの動作は {Next}、{Return}、または {Next,Return} となる。
注: 式の動作を解析する必要はない。 式の動作は常に {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} } // loop 複文全体の動作 {Next, Return} } // 関数全体の動作 {Next}
fn switch_example () { var a : i32= 0 ; switch a { default : { break ; // 動作: {Break} } } // switch が Break を Next で置き換えるため、動作は {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ループは、条件付き break を伴うloopへ脱糖される。
前の例で示したように、条件付き 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 は 1 種類のアサーション、 const アサーションを定義する。
'const_assert' expression
10.1. Const アサーション文
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 ; // 無効。式は const 式でなければならない。 }
11. 関数
関数は、呼び出されたときに計算処理を実行する。
関数は次のいずれかの方法で呼び出される:
-
関数呼び出し式を評価する。§ 8.11 関数呼び出し式を参照。
-
関数呼び出し文を実行する。§ 9.5 関数呼び出し文を参照。
-
エントリーポイント関数は、 パイプライン内の シェーダーステージの処理を実行するために、 WebGPU 実装によって呼び出される。 § 13 エントリーポイントを参照。
WGSL 内の関数は、使用箇所よりソース上で後にある場合も含め、任意の順序で定義できる。 このため、関数プロトタイプまたは前方宣言は必要なく、それらを記述する方法もない。
関数には次の 2 種類がある:
-
組み込み関数は WGSL 実装によって提供され、 WGSL モジュールで常に利用できる。 § 17 組み込み関数を参照。
-
ユーザー定義関数は、 WGSL モジュール内で宣言される。
11.1. ユーザー定義関数の宣言
関数宣言は、次の項目を指定することにより、 ユーザー定義関数を作成する:
-
省略可能な属性の集合。
-
関数の名前。
-
仮パラメーターリスト。コンマで区切られ、丸括弧で囲まれた、 0 個以上の仮パラメーター宣言の順序付き列。
-
関数がエントリーポイントである場合、 パラメーターをシェーダーステージ入力として指定するために、 パラメーターへ属性を付けることができる。
-
-
省略可能な戻り値の型。
-
関数がエントリーポイントである場合、 シェーダーステージ出力を指定するために、 戻り値の型へ属性を付けることができる。
-
-
関数本体。 これは、関数が呼び出されたときに実行される文の集合である。
関数宣言はモジュールスコープでのみ 行わなければならない。 関数名はプログラム全体でスコープ内となる。
注: 各ユーザー定義関数は、 1 つのオーバーロードだけを持つ。
仮パラメーターの 宣言は、関数を呼び出す際に指定 しなければならない値について、 識別子の名前と型を指定する。 エントリーポイント関数の仮パラメーターには属性を付けることができる。 § 11.2 関数呼び出しを参照。 識別子のスコープは、 関数本体である。 ある関数の 2 つの仮パラメーターが同じ名前を持っては ならない。
注: 一部の組み込み関数では、 パラメーターに抽象数値型を使用できることがある。 ただし、この機能は現在、ユーザー宣言関数ではサポートされていない。
戻り値の型を指定する場合、 その型は構築可能で なければならない。
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. 関数呼び出し
関数呼び出しとは、関数を呼び出す文または式である。
関数呼び出しを含む関数を呼び出し元関数、または 呼び出し元と呼ぶ。 呼び出される関数を呼び出し先関数、または 呼び出し先と呼ぶ。
関数呼び出しは:
-
呼び出し先関数の名前を指定し、
-
丸括弧で囲まれた、コンマ区切りの引数値式のリストを指定する。
関数呼び出しは、呼び出し先関数内の 仮パラメーターと同じ数の引数値を指定 しなければならない。 各引数値は、位置によって対応する仮パラメーターと同じ型へ評価され なければならない。
要約すると、関数を呼び出すとき:
呼び出し先関数は、次のように戻る:
詳細には、関数呼び出しが実行されると次の手順が行われる:
-
関数呼び出しの引数値を評価する。 相対的な評価順序は左から右である。
-
呼び出し先関数がユーザー定義である場合、 呼び出し先関数内の各関数スコープ変数にメモリを割り当てる。
-
初期化は§ 7.3 var 宣言の説明に従って行われる。
-
-
関数呼び出しの引数値を位置によって対応付け、 呼び出し先関数の仮パラメーターの値を決定する。 たとえば、呼び出し先関数の最初の仮パラメーターは、 呼び出し場所にある最初の引数の値を持つ。
-
呼び出し先関数が戻るまで実行する。
-
制御を呼び出し元関数へ戻し、呼び出し元関数の実行を再開する。 呼び出し先関数が値を返す場合、 その値を関数呼び出し式の値として使用する。
関数呼び出しの位置を呼び出し場所と呼ぶ。 具体的には、解析されたcall_phrase文法規則のインスタンスにおける、 最初のトークンの位置である。 呼び出し場所は動的コンテキストである。 したがって、同じテキスト上の位置が複数の呼び出し場所を表すことがある。
注: フラグメントシェーダー内の関数呼び出しは、 クアッド内の すべての呼び出しが破棄された場合、戻らない可能性がある。 その場合、制御は呼び出し元関数へ戻されない。
11.3. const関数
const属性を付けて宣言された関数は、 シェーダー作成時に評価できる。 これらの関数をconst 関数と呼ぶ。 これらの関数の呼び出しは、const 式の一部にできる。
関数にconst 式ではない式、または const 宣言ではない宣言が含まれる場合、 シェーダー作成エラーとなる。
注: const属性を、 ユーザー宣言関数へ適用することはできない。
const first_one = firstLeadingBit ( 1234 + 4567 ); // 12 と評価される // firstLeadingBit は AbstractInt を // 操作できないため、first_one の型は // i32 となる @id ( 1 ) override x : i32; override y = firstLeadingBit ( x ); // const 式は override 式で // 使用できる。 // このコンテキストでは firstLeadingBit(x) は // const 式ではない。 fn foo () { var a : array< i32, firstLeadingBit ( 257 ) > ; // すべてのパラメーターが const 式である場合、 // const 関数を const 式内で // 使用できる。 }
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のルート識別子である。
-
EがbufferViewまたは bufferArrayView組み込み呼び出しである場合、 ルート識別子はポインター引数のルート識別子である。
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 ); // 無効。1 つ以上が書き込まれる場合、 // 同じルート識別子を持つ 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
属性の説明で明示的に許可されている場合を除き、 1 つのオブジェクトまたは型に同じ属性を複数回指定しては ならない。
12.1. align
'@' 'align' '(' expression ',' ?
')'
| 説明 |
メモリ内における構造体メンバーの配置を制約する。
この属性は、包含する構造体型の値がメモリ内にどのように現れ得るかに影響する。 つまり、構造体自体とその構成メンバーが現れ得るバイトアドレスを制約する。 align(n)が、
型Tを持つSのメンバーへ適用され、
Sがアドレス空間ASにある変数の
格納型となることができ、
ASがuniformでない場合、
nは次を満たさ
なければならない:
ある正の整数kについて、 n = k × RequiredAlignOf(T,AS)。 アラインメントとサイズの規則は相互再帰的である。 ただし、上記の制約は入れ子になった型に必要なアラインメントに依存し、 型の入れ子の深さには上限があるため、 適切に定義されている。 uniformまたは storageバッファーへ バインドされたメモリの開始アドレスのアラインメントが、 属性で指定された値より低い場合、結果のアラインメントは両者の最小値となる。 実装は、変数のベースアドレスを基準としてのみ属性を満たす。 § 14.4 メモリレイアウトを参照。 |
| パラメーター | i32または
u32へ
解決される
const 式で
なければならない。 正でなければならない。 2 の累乗でなければならない。 |
12.2. binding
'@' 'binding' '(' expression ',' ?
')'
| 説明 | バインドグループ内における リソースのバインディング番号を指定する。 § 13.3.2 リソースインターフェースを参照。 |
| パラメーター | i32または
u32へ
解決される
const 式で
なければならない。 非負でなければならない。 |
12.3. blend_src
'@' 'blend_src' '(' expression ',' ?
')'
| 説明 |
機能dual_source_blendingが
有効な場合に、フラグメント出力の一部を指定する。
§ 13.3.1.3 入出力ロケーションを参照。
location属性を持つ 構造体型のメンバーにのみ適用 しなければならない。 数値スカラー型または 数値ベクトル型のオブジェクトの宣言にのみ適用 しなければならない。 シェーダーステージ入力に含めては ならない。 フラグメントシェーダーステージを除き、 シェーダーステージ出力に含めては ならない。 |
| パラメーター | 値が0または1である
i32または
u32へ
解決される
const 式で
なければならない。
|
12.4. builtin
'@' 'builtin' '(' builtin_value_name ',' ? ')'
| 説明 |
関連付けられたオブジェクトが、指定された
トークンによって示される組み込み値であることを指定する。
§ 13.3.1.1 組み込み入力と出力を参照。
エントリーポイント関数のパラメーター、エントリーポイントの戻り値の型、 または構造体のメンバーにのみ適用 しなければならない。 |
| パラメーター | 組み込み値の 組み込み値の名前トークンで なければならない。 |
12.5. const
'@' 'const'
| 説明 |
関数をconst
関数として使用できることを指定する。
この属性をユーザー定義関数へ適用しては
ならない。
関数宣言にのみ適用 しなければならない。 注: この属性は、どの組み込み関数をconst 式内で使用できるかを説明するための 表記上の規約として使用される。 |
| パラメーター | なし |
12.6. diagnostic
'@' 'diagnostic' diagnostic_control
'(' severity_control_name ',' diagnostic_rule_name ',' ? ')'
| 説明 |
範囲診断フィルターを指定する。
§ 2.3 診断を参照。
1 つの構文形式に複数のdiagnostic属性を指定できるが、 それぞれ異なるトリガー規則を指定 しなければならない。 |
| パラメーター |
最初のパラメーターはseverity_control_nameである。
2 番目のパラメーターは、トリガー規則を指定する diagnostic_rule_nameトークンである。 |
12.7. group
'@' 'group' '(' expression ',' ?
')'
| 説明 | リソースのバインディンググループを指定する。 § 13.3.2 リソースインターフェースを参照。 |
| パラメーター | i32または
u32へ
解決される
const 式で
なければならない。 非負でなければならない。 |
12.8. id
'@' 'id' '(' expression ',' ?
')'
| 説明 |
パイプラインでオーバーライド可能な定数の
代替名として数値識別子を指定する。
スカラー型の override 宣言にのみ適用 しなければならない。 |
| パラメーター | i32または
u32へ
解決される
const 式で
なければならない。 非負でなければならない。 |
12.9. interpolate
'@' 'interpolate' '(' interpolate_type_name ',' ? ')'
| '@' 'interpolate' '(' interpolate_type_name ',' interpolate_sampling_name ',' ? ')'
| 説明 | ユーザー定義 IO をどのように補間 しなければならないかを指定する。 § 13.3.1.4 補間を参照。 |
| パラメーター |
最初のパラメーターは、補間型の
補間型の名前トークンで
なければならない。
2 番目のパラメーターが存在する場合、それは 補間サンプリングの 補間サンプリングの名前トークンで なければならない。 |
12.10. invariant
'@' 'invariant'
| 説明 |
頂点シェーダーのposition
組み込み出力値へ適用すると、
結果の計算は異なるプログラム間、および同じエントリーポイントの異なる呼び出し間で
不変となる。
つまり、異なるエントリーポイント内の 2 つのposition出力について、
データフローと制御フローが一致する場合、結果の値が同一であることが保証される。
position
組み込み入力値には影響しない。
注:
この属性は、HLSL の |
| パラメーター | なし |
12.11. location
'@' 'location' '(' expression ',' ?
')'
| 説明 |
エントリーポイントのユーザー定義 IO の一部を指定する。
§ 13.3.1.3 入出力ロケーションを参照。
エントリーポイント関数のパラメーター、エントリーポイントの戻り値の型、 または構造体型のメンバーにのみ適用 しなければならない。 数値スカラー型または 数値ベクトル型のオブジェクトの宣言にのみ適用 しなければならない。 コンピュート シェーダーステージ入力に含めては ならない。 |
| パラメーター | i32または
u32へ
解決される
const 式で
なければならない。 非負でなければならない。 |
12.12. must_use
'@' 'must_use'
| 説明 |
この関数の呼び出しを
式として使用
しなければならないことを指定する。
つまり、この関数の呼び出しを
関数呼び出し文の全体としては
ならない。
戻り値の型を持つ 関数の宣言にのみ適用 しなければならない。 注:
多くの関数は値を返し、副作用を持たない。
そのような関数の呼び出しだけで関数呼び出し文を構成することは、
多くの場合プログラミング上の不具合である。
これらの性質を持つ組み込み関数は 注:
|
| パラメーター | なし |
12.13. size
'@' 'size' '(' expression ',' ?
')'
| 説明 |
構造体メンバーのために予約するバイト数を指定する。
この数値は、少なくともメンバーの型の バイトサイズで なければならない:
§ 14.4 メモリレイアウトを参照。 構造体型のメンバーにのみ適用 しなければならない。 メンバー型は作成時固定フットプリントを持た なければならない。 |
| パラメーター | i32または
u32へ
解決される
const 式で
なければならない。 正でなければならない。 |
12.14. subgroup_size
'@' 'subgroup_size' '(' expression ',' ? ')'
| 説明 |
コンピュートシェーダー呼び出しのサブグループサイズを指定する。
コンピュートシェーダーの エントリーポイント関数にのみ適用 しなければならない。 |
| 要件 | subgroup_size_control拡張が 有効な場合にのみ使用 しなければならない。 |
| パラメーター |
i32または
u32へ
解決される
const
式または
override 式で
なければならない。 値が 2 の累乗でない場合:
エントリーポイントの 値が 値が |
12.15. workgroup_size
'@' 'workgroup_size' '(' expression ',' ? ')'
| '@' 'workgroup_size' '(' expression ',' expression ',' ?
')'
| '@' 'workgroup_size' '(' expression ',' expression ','
expression ',' ?
')'
| 説明 |
コンピュートシェーダーのワークグループグリッドの x、y、z 次元を指定する。
第1パラメーターは x 次元を指定する。 第2パラメーターが指定されている場合は y 次元を指定し、それ以外の場合は 1 とみなされる。 第3パラメーターが指定されている場合は z 次元を指定し、それ以外の場合は 1 とみなされる。 必ずコンピュートシェーダーのエントリーポイント関数にのみ適用しなければならない。 その他のオブジェクトには適用してはならない。 |
| パラメーター |
1個、2個、または3個のパラメーターを取る。
各パラメーターは必ずconst 式またはoverride 式でなければならない。 すべてのパラメーターは必ず同じ型、すなわち i32 または u32 のいずれかでなければならない。 指定されたパラメーターのいずれかが、非正の値に評価される const 式である場合、 シェーダー作成エラーとなる。 指定されたパラメーターのいずれかが非正の値に評価される場合、WebGPU API が指定する上限を超える場合、またはパラメーター値の積が WebGPU API が指定する上限を超える場合、パイプライン作成エラーとなる(WebGPU § 3.6.2 制限を参照)。 |
12.16. シェーダーステージ属性
以下のシェーダーステージ 属性は、関数を特定のシェーダーステージのエントリーポイントとして指定する。 これらの属性は必ず関数宣言にのみ適用しなければならず、 1つの関数に存在できるのは最大1つである。 これらはパラメーターを取らない。
12.16.1. vertex
'@' 'vertex'
vertex 属性は、その関数をレンダーパイプラインの頂点シェーダー
ステージのエントリーポイントとして宣言する。
12.16.2. fragment
'@' 'fragment'
fragment 属性は、その関数をレンダーパイプラインのフラグメントシェーダー
ステージのエントリーポイントとして宣言する。
12.16.3. compute
'@' 'compute'
compute 属性は、その関数をコンピュートパイプラインのコンピュートシェーダー
ステージのエントリーポイントとして宣言する。
13. エントリーポイント
エントリーポイントとは、 特定のシェーダーステージの処理を実行するユーザー定義関数である。
13.1. シェーダーステージ
WebGPU は、描画またはディスパッチコマンドの形式で GPU に処理を発行する。 これらのコマンドは、シェーダーステージの入力、出力、および アタッチされたリソースの集合をコンテキストとして、 パイプラインを実行する。
パイプラインは、 GPU 上で実行する処理をステージの列として記述し、その一部はプログラム可能である。 WebGPU では、描画またはディスパッチコマンドの実行をスケジュールする前にパイプラインが作成される。 パイプラインには GPUComputePipeline と GPURenderPipeline の2種類がある。
ディスパッチコマンドは、 GPUComputePipeline を使用して、制御可能な並列度を持つ論理的な点のグリッド上で コンピュートシェーダー ステージを実行しながら、バッファーおよび画像リソースを読み取り、場合によっては更新する。
描画コマンドは、GPURenderPipeline を使用して、ほかの固定機能ステージとともに2つのプログラム可能ステージを持つ多段階処理を実行する。
-
頂点シェーダー ステージは、単一の頂点の入力属性をその頂点の出力属性へ写像する。
-
固定機能ステージは頂点をグラフィックプリミティブ(三角形など)へ写像し、 その後それらをラスタライズしてラスタライズフラグメントを生成する。 各ラスタライズフラグメントは、描画されるプリミティブと フレームバッファー内の特定のピクセルとの重なりを表す。
-
フラグメント シェーダーステージは各フラグメントを処理し、 場合によってはフラグメント出力を生成する。
-
通常、各ラスタライズ フラグメントに対して1つのフラグメントシェーダー呼び出しが作成される。 ラスタライズフラグメントが複数のサンプルを覆う場合は、複数のフラグメント呼び出しが作成されることがある。 WebGPU § 23.2.10 サンプル単位シェーディングを参照。
-
ラスタライズフラグメントがプリミティブの境界付近にある場合、追加のヘルパー 呼び出しも作成されることがある。 § 15.4 フラグメントシェーダーと ヘルパー呼び出しを参照。
-
-
固定機能ステージはフラグメント出力を消費し、カラーアタッチメントや深度および ステンシルバッファーなどの外部状態を更新することがある。
WebGPU 仕様では、パイプラインについてさらに詳しく説明している。
WGSL は、パイプラインのプログラム可能な部分に対応する3つのシェーダーステージを定義する。
-
コンピュート
-
頂点
-
フラグメント
各シェーダーステージには、別の箇所で説明する独自の機能と制約がある。
13.2. エントリーポイント宣言
エントリーポイントを作成するには、 シェーダーステージ属性を持つユーザー定義関数を宣言する。
WebGPU API でパイプラインを構成するとき、
エントリーポイントの関数名は WebGPU の GPUProgrammableStage
オブジェクトの entryPoint 属性に対応する。
エントリーポイントの仮 パラメーターは、ステージのシェーダーステージ入力を表す。 構造体型を使用して、ユーザー定義入力同士をグループ化し、必要に応じて組み込み 入力とともにグループ化できる。 各パラメーターは必ずシェーダーステージ入力であるか、 または各構造体メンバーがシェーダーステージ入力である構造体型で必ず宣言されなければならない。
指定されている場合、エントリーポイントの戻り値の型とその属性は、ステージのシェーダーステージ出力を表す。 構造体型を使用して、ユーザー定義出力同士をグループ化し、必要に応じて組み込み 出力とともにグループ化できる。 戻り値の型とその属性が存在する場合、それらは必ずシェーダーステージ出力であるか、 または各構造体メンバーがシェーダーステージ出力である構造体型で必ずなければならない。
注: コンピュートエントリーポイントが戻り値の型を持つことはない。
@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 fn bad_shader () { }
13.3. シェーダーインターフェース
シェーダーインターフェースは、シェーダーがシェーダーステージの外部にあるデータへ読み取りまたは書き込みのために アクセスする際に介するオブジェクトの集合、およびシェーダーの構成に使用されるパイプラインからオーバーライド可能な定数である。 インターフェースには以下が含まれる。
-
アタッチされたリソース。 これには以下が含まれる。
宣言 D は、以下の場合にシェーダーから静的にアクセスされる。
-
D に解決される 識別子が、シェーダーステージ内の関数のいずれかの宣言内に現れる。
-
D に解決される 識別子が、静的にアクセスされる宣言の型を定義するために使用される。
-
D に解決される 識別子が、静的にアクセスされる宣言の初期化子で使用される。
-
D に解決される 識別子が、静的にアクセスされる宣言で使用される属性によって使用される。
-
属性、仮パラメーター、戻り値の型、関数本体を含む関数宣言のすべての部分。
-
型エイリアスをたどることを含め、 上記を定義するために必要なあらゆる型。
-
型の定義を補助する特別な場合として、workgroup アドレス空間内の変数の配列型における要素数であるoverride 式で使用される任意のoverride 宣言。 ただし、その変数自体が静的にアクセスされる場合に限る。
-
上記のいずれかに含まれる override 式の評価を支援するために使用される任意の override 宣言。
-
上記のいずれかに付けられた任意の属性。
これで、シェーダーのインターフェースを以下から構成されるものとして正確に定義できる。
-
エントリーポイントの戻り値。 これはシェーダーステージ出力を表す。
-
シェーダーから静的にアクセスされるユニフォームバッファー、 ストレージバッファー、 テクスチャ リソース、およびサンプラーリソースの変数。
-
シェーダーから静的にアクセスされるoverride 宣言。
-
シェーダーから静的にアクセスされる即時データ変数。
13.3.1. ステージ間の入出力インターフェース
シェーダーステージ入力 とは、パイプラインの上流からシェーダーステージへ提供されるデータである。 各データは組み込み入力値またはユーザー定義入力のいずれかである。
シェーダーステージ 出力とは、パイプラインの下流でさらに処理するためにシェーダーが提供するデータである。 各データは組み込み出力値またはユーザー定義出力のいずれかである。
IO 属性は、オブジェクトをシェーダーステージ入力またはシェーダーステージ出力として確立するため、 あるいは入力または出力の特性をさらに記述するために使用される。 IO 属性は以下のとおりである。
13.3.1.1. 組み込み入力と出力
組み込み入力 値は、システムが生成した制御情報へのアクセスを提供する。 エントリーポイントは、同じ組み込み値名を持つ2つの組み込み入力を持ってはならない。
ステージ S に対する、名前 X、型 TX の組み込み入力には、 シェーダーステージ S のエントリーポイントの仮パラメーターを介して、 以下の2つの方法のいずれかでアクセスする。
-
パラメーターが属性
builtin(X)を持ち、 型 TX である。 -
パラメーターが構造体型を持ち、その構造体メンバーの1つが属性
builtin(X)を持ち、型 TX である。
逆に、エントリーポイントのパラメーターまたはパラメーターのメンバーがbuiltin 属性を持つ場合、 対応する組み込み値は、そのエントリーポイントのシェーダーステージに対する入力でなければならない。
組み込み出力 値は、パイプライン内の後続の処理ステップへ制御情報を伝えるためにシェーダーによって使用される。 エントリーポイントは、同じ組み込み値名を持つ2つの組み込み出力を持ってはならない。
ステージ S に対する、名前 Y、型 TY の組み込み出力は、 シェーダーステージ S のエントリーポイントの戻り値を介して、以下の2つの方法のいずれかで設定される。
-
エントリーポイントの戻り値の型が属性
builtin(Y)を持ち、型 TY である。 -
エントリーポイントの戻り 値の型が構造体型を持ち、その構造体メンバーの1つが属性
builtin(Y)を持ち、型 TY である。
逆に、エントリーポイントの戻り値の型または戻り値の型のメンバーがbuiltin 属性を持つ場合、 対応する組み込み値は、そのエントリーポイントのシェーダーステージに対する出力でなければならない。
注: position 組み込み値は、 頂点シェーダーの出力であると同時に、フラグメントシェーダーへの入力でもある。
組み込み入力値と組み込み出力値を総称して組み込み値という。
次の表は、利用可能な組み込み値をまとめたものである。 それぞれは、組み込み値に対する組み込み値名のトークンである。 それぞれの詳細は後続の節で説明する。
| 名前 | ステージ | 方向 | 型 | 拡張 |
|---|---|---|---|---|
| vertex_index | 頂点 | 入力 | u32 | |
| instance_index | 頂点 | 入力 | u32 | |
| clip_distances | 頂点 | 出力 | array<f32, N>(N ≤ 8)
| clip_distances |
| position | 頂点 | 出力 | vec4<f32> | |
| フラグメント | 入力 | vec4<f32> | ||
| front_facing | フラグメント | 入力 | bool | |
| frag_depth | フラグメント | 出力 | f32 | |
| primitive_index | フラグメント | 入力 | u32 | primitive_index |
| sample_index | フラグメント | 入力 | u32 | |
| sample_mask | フラグメント | 入力 | u32 | |
| フラグメント | 出力 | u32 | ||
| local_invocation_id | コンピュート | 入力 | vec3<u32> | |
| local_invocation_index | コンピュート | 入力 | u32 | |
| global_invocation_id | コンピュート | 入力 | vec3<u32> | |
| global_invocation_index | コンピュート | 入力 | u32 | linear_indexing |
| workgroup_id | コンピュート | 入力 | vec3<u32> | |
| workgroup_index | コンピュート | 入力 | u32 | linear_indexing |
| num_workgroups | コンピュート | 入力 | vec3<u32> | |
| subgroup_invocation_id | コンピュート | 入力 | u32 | subgroups |
| フラグメント | ||||
| subgroup_size | コンピュート | 入力 | u32 | subgroups |
| フラグメント | ||||
| subgroup_id | コンピュート | 入力 | u32 | subgroups および subgroup_id |
| num_subgroups | コンピュート | 入力 | 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 |
| ステージ | 頂点 |
| 型 | array<f32, N> |
| 方向 | 出力 |
| 説明 |
配列内の各値は、ユーザー定義のクリップ平面までの距離を表す。クリップ距離
0 は頂点が平面上にあることを意味し、正の距離は頂点がクリップ
半空間の内側にあることを意味し、負の距離は頂点がクリップ半空間の外側にあることを意味する。
clip_distances の配列サイズは必ず ≤ 8 でなければならない。
WebGPU § 23.2.4
プリミティブのクリッピングを参照。
|
13.3.1.1.2. frag_depth
| 名前 | frag_depth |
| ステージ | フラグメント |
| 型 | f32 |
| 方向 | 出力 |
| 説明 |
ビューポート深度範囲内における、更新されたフラグメントの深度。
WebGPU § 3.3 座標系を参照。 fragment_depth 機能がサポートされている場合、 builtin 属性には、深度モードを指定するための省略可能な第2パラメーターを指定できる。
フラグメントの元の深度とは、フラグメントのRasterizationPoint の depth プロパティである。 シェーダーが深度モードの保証に違反する深度値を返した場合、代わりに不定の深度値が使用されることがある。
|
13.3.1.1.3. front_facing
| 名前 | front_facing |
| ステージ | フラグメント |
| 型 | bool |
| 方向 | 入力 |
| 説明 | 現在のフラグメントが前面プリミティブ上にある場合は true。 それ以外の場合は false。 |
13.3.1.1.4. global_invocation_id
| 名前 | global_invocation_id |
| ステージ | コンピュート |
| 型 | vec3<u32> |
| 方向 | 入力 |
| 説明 | 現在の呼び出しのグローバル呼び出し ID、すなわちコンピュートシェーダーグリッド内の位置。 global_invocation_id の値は、 workgroup_id * workgroup_size + local_invocation_id に等しい。 |
13.3.1.1.5. global_invocation_index
| 名前 | global_invocation_index |
| ステージ | コンピュート |
| 型 | u32; |
| 方向 | 入力 |
| 説明 |
現在の呼び出しのグローバル呼び出しインデックス、すなわちコンピュートシェーダーグリッド内の線形位置。
global_invocation_index
の値は、以下に等しい。
global_invocation_id.x +
注: ディスパッチされるワークグループ数によってこの値が
u32
型の範囲を超える場合、ディスパッチは失敗する。
|
13.3.1.1.6. instance_index
| 名前 | instance_index |
| ステージ | 頂点 |
| 型 | u32 |
| 方向 | 入力 |
| 説明 |
現在の API レベルの描画コマンド内における、現在の頂点のインスタンスインデックス。
最初のインスタンスは、直接または間接のいずれで指定されたかにかかわらず、
描画の |
13.3.1.1.7. local_invocation_id
| 名前 | local_invocation_id |
| ステージ | コンピュート |
| 型 | vec3<u32> |
| 方向 | 入力 |
| 説明 | 現在の呼び出しのローカル呼び出し ID、すなわちワークグループ グリッド内の位置。 |
13.3.1.1.8. local_invocation_index
| 名前 | local_invocation_index |
| ステージ | コンピュート |
| 型 | u32 |
| 方向 | 入力 |
| 説明 | 現在の呼び出しのローカル呼び出しインデックス。 これはワークグループグリッド内における呼び出しの位置を線形化したインデックスである。 |
13.3.1.1.9. num_workgroups
| 名前 | num_workgroups |
| ステージ | コンピュート |
| 型 | vec3<u32> |
| 方向 | 入力 |
| 説明 |
API によってディスパッチされた
コンピュートシェーダーのディスパッチサイズ
vec3<u32>(group_count_x, group_count_y, group_count_z)。
|
13.3.1.1.10. position
| 名前 | position |
| ステージ | 頂点 |
| 型 | 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 |
| ステージ | フラグメント |
| 型 | u32 |
| 方向 | 入力 |
| 説明 | 現在の描画操作の開始以降に現在のインスタンスについて処理されたプリミティブ数に基づく、 プリミティブ単位のインデックス。0 から始まり、点、線、または三角形プリミティブが 処理されるたびに1ずつ増加する。描画されるインスタンスごとに 0 にリセットされる。 プリミティブ再開値によってストリッププリミティブを 再開しても、プリミティブインデックスには影響しない。このインデックスは、 プリミティブのすべてのフラグメントにわたって一様である。 |
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 |
| ステージ | フラグメント |
| 型 | u32 |
| 方向 | 出力 |
| 説明 | 現在のフラグメントに対するサンプルカバレッジマスクの制御。 この変数へ最後に書き込まれた値がシェーダー出力マスクとなる。 書き込まれた値のゼロのビットにより、カラーアタッチメント内の対応するサンプルが破棄される。 |
13.3.1.1.14. vertex_index
| 名前 | vertex_index |
| ステージ | 頂点 |
| 型 | u32 |
| 方向 | 入力 |
| 説明 |
描画のインスタンス化に依存しない、現在の API レベルの描画コマンド内における
現在の頂点のインデックス。
インデックスなし描画の場合、最初の頂点は、直接または間接のいずれで指定されたかにかかわらず、
描画の インデックス付き描画の場合、インデックスは、その頂点に対するインデックスバッファーの
エントリーに、直接または間接のいずれで指定されたかにかかわらず、
描画の |
13.3.1.1.15. workgroup_id
| 名前 | workgroup_id |
| ステージ | コンピュート |
| 型 | vec3<u32> |
| 方向 | 入力 |
| 説明 |
現在の呼び出しのワークグループ
ID、すなわち全体のコンピュートシェーダーグリッド内における
ワークグループの位置。
同じワークグループ内のすべての呼び出しは、同じワークグループ 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 |
| ステージ | コンピュート |
| 型 | u32 |
| 方向 | 入力 |
| 説明 |
現在の呼び出しのワークグループインデックス、すなわち全体のコンピュートシェーダーグリッド内における
ワークグループの線形位置。
同じワークグループ内のすべての呼び出しは、同じワークグループインデックスを持つ。
注: ディスパッチされるワークグループ数によって
この値が u32
型の範囲を超える場合、ディスパッチは失敗する。
|
13.3.1.1.17. subgroup_invocation_id
| 名前 | subgroup_invocation_id |
| ステージ | コンピュートまたはフラグメント |
| 型 | u32 |
| 方向 | 入力 |
| 説明 |
現在の呼び出しのサブグループ呼び出し ID。
ID は [0, subgroup_size - 1] の範囲内にある。 コンピュートシェーダーでは、ID はゼロから始まり、 欠番なく連続する。すなわち、コンピュートシェーダーが実行を開始すると、 各サブグループ内では次のようになる。
注: フラグメントシェーダー内のサブグループ呼び出しインデックスは、 欠番なく連続するとは限らない。実装は、番号の小さい ID の一部をヘルパー呼び出しに割り当てることがある。 |
13.3.1.1.18. subgroup_size
| 名前 | subgroup_size |
| ステージ | コンピュートまたはフラグメント |
| 型 | u32 |
| 方向 | 入力 |
| 説明 |
現在の呼び出しが属するサブグループのサブグループサイズ。
subgroup_size 属性を持つコンピュートシェーダーでは、 この値は指定された属性値に等しい。 |
13.3.1.1.19. subgroup_id
| 名前 | subgroup_id |
| ステージ | コンピュート |
| 型 | u32 |
| 方向 | 入力 |
| 説明 |
ワークグループ内における、
現在の呼び出しが属するサブグループのサブグループ ID。
ID は [0, num_subgroups - 1] の範囲内にある。 |
13.3.1.1.20. num_subgroups
| 名前 | num_subgroups |
| ステージ | コンピュート |
| 型 | u32 |
| 方向 | 入力 |
| 説明 | 現在の呼び出しが属するワークグループ内のサブグループ数。 |
13.3.1.2. ユーザー定義の入力と出力
ユーザー定義データは、パイプラインの開始位置へ入力として渡したり、 パイプラインのステージ間で渡したり、パイプラインの末尾から出力したりできる。
各ユーザー定義 入力データおよび ユーザー定義 出力データは、次の条件を満たさなければならない。
-
IO ロケーションが割り当てられていること。§ 13.3.1.3 入出力ロケーションを参照。
コンピュートシェーダーは、 ユーザー定義の入力または出力を持ってはならない。
13.3.1.3. 入出力ロケーション
各入出力ロケーションは、最大16バイトのサイズの値を格納できる。 型のバイトサイズは、§ 14.4.1 整列とサイズの SizeOf 列を使用して定義される。 たとえば、浮動小数点値の4成分ベクトルは、単一のロケーションを占有する。
IO ロケーションは、location 属性を介して指定される。
ユーザー定義の各入力および出力には、 明示的に指定された IO ロケーションがなければならない。 エントリーポイント IO の各構造体メンバーは、組み込み値 (§ 13.3.1.1 組み込み入力と出力を参照)であるか、 ロケーションを割り当てられているかのいずれかでなければならない。
-
members 内のいずれかのエントリーがblend_src 属性を指定する場合、 members は デュアルソースブレンディングを使用しなければならない。これは次を意味する。
-
members は、
@location(0) @blend_src(0)を持つものと@location(0) @blend_src(1)を持つものの、ちょうど2個のエントリーを含まなければならない。 -
すべての members は同じデータ型を持たなければならない。
-
注: ロケーション番号は入力と出力とで別々である。 エントリーポイントのシェーダーステージ入力のロケーション番号は、 そのエントリーポイントのシェーダーステージ出力のロケーション番号と競合しない。
注: エントリーポイントの出力内でロケーションが重複することを防ぐための追加規則は必要ない。 出力が構造体の場合、上記の最初の規則が重複を防ぐ。 それ以外の場合、出力はスカラーまたはベクトルであり、割り当てることのできるロケーションは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 // 無効。location は構造体型に適用できない。 fn fragShader1 ( @location ( 0 ) in1 : D ) { // ... } @fragment // 無効。in1 と in2 はロケーションを共有できない。 fn fragShader2 ( @location ( 0 ) in1 : f32, @location ( 0 ) in2 : f32) { // ... } @fragment // 無効。location は構造体に適用できない。 fn fragShader3 ( @location ( 0 ) in1 : vec4< f32> ) -> @location ( 0 ) D { // ... }
13.3.1.4. 補間
作者は、interpolate 属性を使用して、 ユーザー定義 IO データがどのように補間されるかを制御できる。 WGSL では、補間の型と補間のサンプリングという2つの側面を制御できる。
補間型は、 次の補間型名のトークンのいずれかでなければならない。
- perspective
-
値は透視補正された方法で補間される。
- linear
-
値は透視補正を行わない線形方式で補間される。
- flat
-
値は補間されない。
補間 サンプリングは、次の補間サンプリング名のトークンのいずれかでなければならない。
- center
-
補間はピクセルの中心で実行される。
- centroid
-
補間は、現在のプリミティブ内でフラグメントが覆うすべてのサンプルの 内部に位置する点で実行される。 この値はプリミティブ内のすべてのサンプルで同じである。
- sample
-
補間はサンプルごとに実行される。 この属性が適用されると、フラグメントシェーダーはサンプルごとに1回呼び出される。
- first
-
値はプリミティブの最初の頂点によって提供される。
- either
-
値はプリミティブの最初の頂点または最後の頂点によって提供される。 値が最初の頂点と最後の頂点のどちらから取得されるかは、実装に依存する。
スカラーまたはベクトルの浮動小数点型のユーザー定義 IO については、次のとおりである。
-
補間属性が指定されていない場合、
@interpolate(perspective, center)とみなされる。 -
補間属性に補間型が指定されている場合、次のようになる。
スカラーまたはベクトルの整数型であるユーザー定義の頂点出力およびフラグメント入力には、
常に補間型 flat を指定しなければならない。
ステージ間インターフェース検証は、 レンダーパイプライン内で、ユーザー定義の各フラグメント入力の補間特性が、同じlocation 割り当てを持つ頂点出力の補間特性と 一致することを検査する。 一致しない場合、パイプライン作成エラーが発生する。
13.3.2. リソースインターフェース
リソースとは、 シェーダーステージの外部にあるデータへのアクセスを提供するオブジェクトであり、 override 宣言でも、 即時データ変数でも、 シェーダーステージ入力または出力でもない。 リソースはシェーダーのすべての呼び出しによって共有される。
リソースには次の4種類がある。
シェーダーの リソースインターフェースは、シェーダーステージ内の関数から静的にアクセスされるモジュールスコープの リソース変数の集合である。
各リソース変数は、group 属性とbinding 属性の両方を付けて宣言しなければならない。 これらはシェーダーのステージとともに、シェーダーのパイプライン上における リソースのバインディングアドレスを識別する。 WebGPU § 8.3 GPUPipelineLayoutを参照。
即時データ変数は、group 属性またはbinding 属性を使用しない。
シェーダー内の 2つの異なるリソース変数は、対として考えたときに同じgroup 値とbinding 値を持ってはならない。
13.3.3. リソースレイアウトの互換性
WebGPU は、シェーダーのリソースインターフェースが、そのシェーダーを使用する パイプラインのレイアウトと 一致することを要求する。
リソースインターフェース内の WGSL 変数が、互換性のない WebGPU のバインディングメンバーまたはバインディング型へバインドされている場合、 パイプライン作成エラーとなる。 ここで互換性は次の表によって定義される。
インターフェース検証の要件については、WebGPU API 仕様を参照。
13.3.4. バッファーバインディングによる実行時サイズ配列の要素数の決定
ストレージバッファー変数が実行時サイズ配列を含む場合、その配列の要素数は、
対応する resource
のサイズから決定される。
T をストレージバッファー変数の格納型とする。 ここで T は、実行時サイズ配列型であるか、実行時サイズ配列型を含む。
bufferBinding をバッファーバインディングとして取得(
resource) とする。EBS を、ストレージバッファー変数に対応するパイプラインバインディングアドレスへ バインドされた bufferBinding の有効バッファーバインディングサイズ とする。
このとき、NRuntime、すなわち実行時サイズ配列の要素数は、 SizeOf(T) ≤ EBS を満たす 最大の整数である。
より詳しくは、型 RAT の実行時サイズ配列に対するNRuntime は次のとおりである。
truncate((EBBS − array_offset) ÷ array_stride)。ここで次のとおりである。
EBBS は、変数に関連付けられた有効バッファーバインディングサイズである。
array_offset は、変数の格納型内における実行時サイズ配列のバイトオフセットである。
格納型が実行時サイズ配列型そのものである RAT の場合はゼロである。
それ以外の場合、格納型は構造体であり、その最後のメンバーが実行時サイズ配列である。 この場合、array_offset は構造体内における そのメンバーのバイトオフセットである。
array_stride は配列型のストライド、すなわちStrideOf(RAT) である。
シェーダーは、arrayLength 組み込み関数を介してNRuntime を算出できる。
NRuntime は、対応するバッファーバインディングのサイズによって決定され、 そのサイズは描画またはディスパッチコマンドごとに異なる場合がある。
WebGPU の検証規則により、1 ≤ NRuntime であることが保証される。
-
weights変数はストレージバッファーである。 -
その格納型は、実行時サイズ配列型
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変数はストレージバッファーである。 -
その格納型は
LightStorageである。 -
LightStorageのpointメンバーは、 型array<PointLight>の実行時サイズ配列である。
struct PointLight { // 整列(16) サイズ(32) position: vec3f, // オフセット(0) 整列(16) サイズ(12) // -- 暗黙的なメンバー整列のパディング -- // オフセット(12) サイズ(4) color : vec3f, // オフセット(16) 整列(16) サイズ(12) // -- 暗黙的な構造体サイズのパディング -- // オフセット(28) サイズ(4) } struct LightStorage { // 整列(16) pointCount : u32, // オフセット(0) 整列(4) サイズ(4) // -- 暗黙的なメンバー整列のパディング -- // オフセット(4) サイズ(12) point : array< PointLight > , // オフセット(16) 整列(16) 要素サイズ(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 では、格納可能型の値を、後から取得するためにメモリへ格納できる。 この節では、メモリの構造と、メモリへアクセスする操作の意味論について説明する。 メモリに配置できる値の型と、メモリアクセスの実行に使用される型については、 § 6.5 メモリビューを参照。
14.1. メモリロケーション
メモリは、互いに異なるメモリロケーションの集合から構成される。 各メモリロケーションのサイズは8ビットである。 メモリに影響する操作は、1つ以上のメモリロケーションの集合と相互作用する。 複合値に対するメモリ操作は、パディング用のメモリロケーションへアクセスしない。 したがって、操作がアクセスするメモリロケーションの集合は連続していないことがある。
2つのメモリロケーションの集合は、それらの共通部分が空でない場合に重複する。
14.2. メモリアクセスモード
メモリアクセスとは、 メモリロケーションに作用する操作である。
-
読み取りアクセスは、メモリロケーションの内容を観測する。
-
書き込みアクセスは、メモリロケーションの内容を設定する。
単一の操作は、読み取り、書き込み、または読み書きの両方を行うことができる。
特定のメモリロケーションは、メモリのアクセスモードとして表される、特定の種類のアクセスだけを サポートすることがある。
| アクセスモード | サポートされるアクセス |
|---|---|
| read | 読み取りアクセスをサポートするが、書き込みはサポートしない。 |
| write | 書き込みアクセスをサポートするが、読み取りはサポートしない。 |
| read_write | 読み取りアクセスと書き込みアクセスの両方をサポートする。 |
WGSL は、列挙子 read、write、および
read_write を事前宣言する。
14.3. アドレス空間
メモリロケーションは、アドレス空間に分割される。 各アドレス空間には、可変性、可視性、格納できる値、およびそこで変数を使用する方法を 決定する固有の特性がある。 詳細については、§ 7 変数および値の宣言を参照。
特定のメモリビューのアクセスモードは、 多くの場合コンテキストによって決定される。
storage アドレス空間は、 read とread_write の両方のアクセスモードをサポートする。 その他の各アドレス空間は、1つのアクセスモードだけをサポートする。 各アドレス空間の既定のアクセスモードを次の表に示す。
| アドレス空間 | 呼び出し間の共有 | 既定のアクセスモード | 注記 |
|---|---|---|---|
| function | 同じ呼び出し内のみ | read_write | |
| private | 同じ呼び出し内のみ | read_write | |
| workgroup | 同じコンピュートシェーダーのワークグループ内の呼び出し | read_write | 最外側の配列の要素数には、パイプラインからオーバーライド可能な定数を指定できる。 |
| uniform | 同じシェーダーステージ内の呼び出し | read | ユニフォームバッファー変数用 |
| storage | 同じシェーダーステージ内の呼び出し | read | ストレージバッファー変数用 |
| immediate | 同じシェーダーステージ内の呼び出し | read | 即時データ変数用。 各エントリーポイントが静的にアクセスできる即時変数は最大1つである。 |
| handle | 同じシェーダーステージ内の呼び出し | read | サンプラー変数およびテクスチャ変数用。 |
WGSL は、handle アドレス空間を除く各アドレス空間について、
列挙子を事前宣言する。
workgroup アドレス空間内の変数には、 コンピュートシェーダーステージ内でのみ静的にアクセスしなければならない。
storage
アドレス空間内の変数(ストレージバッファー)に頂点シェーダーステージから静的にアクセスできるのは、
アクセスモードがread の場合だけである。
格納型が、
write またはread_write のアクセスモードを持つストレージテクスチャである変数には、頂点シェーダーステージから静的にアクセスできない。
WebGPU の createBindGroupLayout()
を参照。
注: 各アドレス空間のパフォーマンス特性は異なる場合がある。
WGSL ソース内で変数宣言またはポインター型を記述する場合、次のようになる。
14.4. メモリレイアウト
WGSL における型のレイアウトは、アドレス空間に依存しない。 ただし厳密にいえば、そのレイアウトを観測できるのはホスト共有可能な バッファーだけである。 ユニフォームバッファー変数とストレージバッファー変数は、メモリ内でバイト列として 構成された大容量データを共有するために使用される。 バッファーは、CPU と GPU の間、パイプライン内の異なるシェーダーステージ間、 または異なるパイプライン間で共有される。
バッファーデータは再フォーマットまたは変換されることなく共有されるため、 バッファーの生成側と消費側がメモリレイアウトについて合意していない場合、動的エラーとなる。 メモリレイアウトとは、バッファー内のバイトを型付き WGSL 値としてどのように構成するかの記述である。 これらのバイトは、共通の基準ロケーションに対する値のメモリロケーションである。
バッファー変数の格納型は、以下で説明する完全に展開されたメモリレイアウトを持つ、 ホスト共有可能な型でなければならない。
各バッファー変数は、uniform またはstorage のいずれかのアドレス空間で宣言しなければならない。
型のメモリレイアウトが重要となるのは、次のものを含む式を評価する場合だけである。
8ビットのバイトは、ホスト共有可能なメモリの最も基本的な単位である。 この節で定義する用語は、8ビットバイトの個数を表す。
次の表記を使用する。ここで、 T はホスト共有可能または固定フットプリントの型、 S はホスト共有可能または固定フットプリントの構造体型、 A はホスト共有可能または固定フットプリントの配列、あるいは実行時サイズ配列である。
-
AlignOfMember(S, i) は、 S の i 番目のメンバーの整列である。
-
SizeOf(T) は、 T のバイトサイズである。
-
SizeOfMember(S, i) は、 S の i 番目のメンバーのサイズである。
-
OffsetOfMember(S, i) は、 S の先頭から i 番目のメンバーまでのオフセットである。
-
StrideOf(A) は、A の要素ストライドであり、 ある配列要素の先頭から次の要素の先頭までのバイト数として定義される。 これは、配列の要素型のサイズを、その要素型の整列まで切り上げた値に等しい。
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の累乗である。
型または構造体メンバーのバイトサイズとは、その型または構造体メンバーの値を格納するために、 ホスト共有可能なメモリ内に予約される連続したバイト数である。 サイズには、型の末尾にあるアドレス指定不可能なパディングが含まれることがある。 したがって、値のロードおよびストアがアクセスするメモリロケーションの数は、 その値のサイズより少ない場合がある。
ホスト共有可能型および固定フットプリント型の整列とサイズは、 次の表で再帰的に定義される。
| ホスト共有可能または固定フットプリントの型 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 |
| メンバー M1...MN を持つstruct S | 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 の実行時に決定される要素数である |
| buffer<N> | 該当なし | N |
| buffer | 該当なし | アタッチされた WebGPU GPUBuffer
のサイズ
|
注: buffer 型は ほかのどの型にも含めることができないため、その整列は無関係である。
bool 値が4バイト整列で4バイトを占有すると規定することにより、
実装はデータ競合を生じさせずに、メモリ内で隣接するブール値をサポートできる。
14.4.2. 構造体メンバーのレイアウト
構造体の内部レイアウトは、 そのメンバーのサイズと整列から算出される。 既定では、メンバーの整列要件を満たしながら、メンバーは重複することなく順番に密に配置される。
この既定の内部レイアウトは、次のレイアウト属性を使用して上書きできる。
構造体型 S の i 番目のメンバーはサイズと整列を持ち、それぞれ SizeOfMember(S, i) および AlignOfMember(S, i) と表記する。 メンバーのサイズと整列は、§ 14.4.4 値の内部レイアウトで 説明するように、構造体の先頭から各メンバーまでのバイトオフセットを算出するために使用される。
S の i 番目のメンバーが属性 size(k) を持つ場合、SizeOfMember(S, i) は k である。 それ以外の場合、メンバーの型を T とすると、 SizeOf(T) である。
S の i 番目のメンバーが属性 align(k) を持つ場合、AlignOfMember(S, i) は k である。 それ以外の場合、メンバーの型を T とすると、 AlignOf(T) である。
構造体メンバーに size 属性が適用されている場合、その値は メンバーの型のサイズ以上でなければならない。
SizeOfMember(S, i) ≥ SizeOf(T)
ここで T は、S の i 番目のメンバーの型である。
最初の構造体メンバーは、構造体の先頭からのバイトオフセットが常にゼロである。
OffsetOfMember(S, 1) = 0
後続の各メンバーは、そのメンバー型の整列を満たし、かつ直前のメンバーとの重複を避ける 最小のオフセットに配置される。 各メンバーインデックス i > 1 について、次のようになる。
OffsetOfMember(S, i) = roundUp(AlignOfMember(S, i ), OffsetOfMember(S, i-1) + SizeOfMember(S, i-1))
struct A { // 整列(8) サイズ(24) u : f32, // オフセット(0) 整列(4) サイズ(4) v : f32, // オフセット(4) 整列(4) サイズ(4) w : vec2< f32> , // オフセット(8) 整列(8) サイズ(8) x : f32// オフセット(16) 整列(4) サイズ(4) // -- 暗黙的な構造体サイズのパディング -- // オフセット(20) サイズ(4) } struct B { // 整列(16) サイズ(160) a : vec2< f32> , // オフセット(0) 整列(8) サイズ(8) // -- 暗黙的なメンバー整列のパディング -- // オフセット(8) サイズ(8) b : vec3< f32> , // オフセット(16) 整列(16) サイズ(12) c : f32, // オフセット(28) 整列(4) サイズ(4) d : f32, // オフセット(32) 整列(4) サイズ(4) // -- 暗黙的なメンバー整列のパディング -- // オフセット(36) サイズ(4) e : A , // オフセット(40) 整列(8) サイズ(24) f : vec3< f32> , // オフセット(64) 整列(16) サイズ(12) // -- 暗黙的なメンバー整列のパディング -- // オフセット(76) サイズ(4) g : array< A , 3 > , // 要素ストライド 24 オフセット(80) 整列(8) サイズ(72) h : i32// オフセット(152) 整列(4) サイズ(4) // -- 暗黙的な構造体サイズのパディング -- // オフセット(156) サイズ(4) } @group ( 0 ) @binding ( 0 ) var < storage, read_write> storage_buffer : B ;
struct A { // 整列(8) サイズ(32) u : f32, // オフセット(0) 整列(4) サイズ(4) v : f32, // オフセット(4) 整列(4) サイズ(4) w : vec2< f32> , // オフセット(8) 整列(8) サイズ(8) @size ( 16 ) x : f32// オフセット(16) 整列(4) サイズ(16) } struct B { // 整列(16) サイズ(208) a : vec2< f32> , // オフセット(0) 整列(8) サイズ(8) // -- 暗黙的なメンバー整列のパディング -- // オフセット(8) サイズ(8) b : vec3< f32> , // オフセット(16) 整列(16) サイズ(12) c : f32, // オフセット(28) 整列(4) サイズ(4) d : f32, // オフセット(32) 整列(4) サイズ(4) // -- 暗黙的なメンバー整列のパディング -- // オフセット(36) サイズ(12) @align ( 16 ) e : A , // オフセット(48) 整列(16) サイズ(32) f : vec3< f32> , // オフセット(80) 整列(16) サイズ(12) // -- 暗黙的なメンバー整列のパディング -- // オフセット(92) サイズ(4) g : array< A , 3 > , // 要素ストライド 32 オフセット(96) 整列(8) サイズ(96) h : i32// オフセット(192) 整列(4) サイズ(4) // -- 暗黙的な構造体サイズのパディング -- // オフセット(196) サイズ(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 = ストライド * 要素数 = 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 = ストライド * 要素数 = 16 * 8 var bigger_stride : array< vec3< f32> , 8 > ;
// 次の配列: // - 整列は 4 = AlignOf(f32) // - 要素ストライドは 4 = roundUp(AlignOf(f32),SizeOf(f32)) = 4 // B が描画またはディスパッチコマンドのバインディングに対する // 有効バッファーバインディングサイズである場合、要素数は次のとおり: // N_runtime = floor(B / 要素ストライド) = 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 が描画またはディスパッチコマンドのバインディングに対する // 有効バッファーバインディングサイズである場合、要素数は次のとおり: // N_runtime = floor(B / 要素ストライド) = floor(B / 16) var < storage> directions : array< vec3< f32>> ;
14.4.4. 値の内部レイアウト
この節では、値全体の配置が仮定されている場合に、ホスト共有可能な値の内部が、 バッファーのバイトロケーションにどのように配置されるかを説明する。 これらのレイアウトは値の型、および構造体メンバー上のalign 属性とsize 属性に依存する。 これらの規則は、以下で説明する非不透明型に適用される。 buffer 型の値には内部構造がなく、 これらの規則による制約を受けない。
値が配置されるバッファーのバイトオフセットは、型の整列要件を満たさなければならない。 型 T の値がバッファーオフセット k に配置される場合、 ある非負整数 c について、k = c × AlignOf(T) となる。
データは、アドレス空間にかかわらず同一に現れる。
注: bool 型はホスト共有可能ではない。 WGSL は、bool 値のサイズと整列が 4バイトであると規定するが、bool 値の内部レイアウトは規定しない。
型 u32 またはi32 の値 V が、 ホスト共有バッファーのバイトオフセット 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番目のメンバーは、バイトオフセット k + OffsetOfMember(S,i) に配置される。 § 14.4.2 構造体メンバーのレイアウトを参照。
14.4.5. アドレス空間のレイアウト制約
storage アドレス空間とuniform アドレス空間には、 この節で説明する異なるレイアウト制約がある。
uniform を除くすべてのアドレス空間には、storage アドレス空間と同じ制約がある。
変数から直接または間接的に参照されるすべての構造体型および配列型は、 その変数のアドレス空間の制約に従わなければならない。 アドレス空間の制約への違反は、シェーダー作成エラーとなる。
この節では、アドレス空間 C で使用される場合における、 ホスト共有可能または固定フットプリントの型 S の値に対する バイトオフセットの整列要件を、 RequiredAlignOf(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 である場合、 buffer_view 組み込み関数の結果としての場合を除き禁止される | roundUp(16, AlignOf(S)) buffer_view 組み込み関数の結果としての場合を除き禁止される |
| 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 属性を使用する方法を示す。 特に、これらの手法を使用して、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 メモリモデルにおける メモリ書き込み操作と同等である。
呼び出しが次のいずれかを実行すると、読み取りアクセスが発生する。
-
ロード規則の評価
-
次を除く任意のテクスチャ組み込み関数。
-
atomicStore を除く任意のアトミック組み込み関数
-
workgroupUniformLoad 組み込み関数
呼び出しが次のいずれかを実行すると、書き込みアクセスが発生する。
-
textureStore 組み込み関数
-
atomicLoad を除く任意のアトミック組み込み関数
-
atomicCompareExchangeWeak は、返された結果の
exchangedメンバーがtrueの場合にのみ書き込みを実行する
-
アトミックな読み取り・変更・書き込み組み込み関数は、 読み取りアクセスと書き込みアクセスの両方である 単一のメモリ操作を実行する。
読み取りアクセスと書き込みアクセスは、これ以外の状況では発生しない。 読み取りアクセスと書き込みアクセスを総称して、Vulkan メモリモデルではメモリ操作という。
メモリビューを介したメモリ操作は、通常、そのメモリビューに関連付けられたロケーションの集合だけへアクセスする。 例外として、ベクトルの成分への書き込みアクセスは、そのベクトルに関連付けられた すべてのメモリロケーションへアクセスすることがある。
-
たとえば、複数のメンバーを含む構造体からu32 へアクセスするメモリ読み取りは、 その u32 メンバーに関連付けられたメモリロケーションだけを読み取る。
-
たとえば、3要素ベクトルの第2成分へのメモリ書き込みは、 その第2成分のロケーションへ書き込み、ベクトルの3つの要素すべてを 読み取ること、および書き込むことがある。
スウィズルビューを介したメモリ操作は、 基になるベクトルに関連付けられたすべてのメモリロケーションへアクセスする。 詳細については、スウィズルビューの読み取りおよびスウィズルビューの書き込みを参照。
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 である制御バリアへ対応付けられる。
暗黙的および明示的な微分は、暗黙的なクアッド実行スコープを持つ。
注:
生成されたシェーダーで 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. プライベートと非プライベート
storage
またはworkgroup アドレス空間内の、
アトミックではないすべての読み取りアクセスは、非プライベートとみなされ、
Workgroup スコープで
NonPrivatePointer | MakePointerVisible メモリオペランドを持つ
読み取り操作に対応する。
storage
またはworkgroup アドレス空間内の、
アトミックではないすべての書き込みアクセスは、非プライベートとみなされ、
Workgroup スコープで
NonPrivatePointer | MakePointerAvailable メモリオペランドを持つ
書き込み操作に対応する。
handle
アドレス空間内の、
アトミックではないすべての読み取りアクセスは、非プライベートとみなされ、
Workgroup スコープで
NonPrivateTexel | MakeTexelVisible メモリオペランドを持つ
読み取り操作に対応する。
handle
アドレス空間内の、
アトミックではないすべての書き込みアクセスは、非プライベートとみなされ、
Workgroup スコープで
NonPrivateTexel | MakeTexelAvailable メモリオペランドを持つ
書き込み操作に対応する。
15. 実行
§ 1.1 概要では、シェーダーがどのように呼び出され、 呼び出しへ分割されるかを説明している。 この節では、個別および集合的に呼び出しを実行する方法に対する追加の制約を説明する。
15.1. 呼び出し内のプログラム順序
WGSL モジュール内の各文は、実行中に0回以上実行されることがある。 ある呼び出しについて、特定の文の各実行は固有の動的文インスタンスを表す。
文に式が含まれる場合、その文の意味論は次を決定する。
-
式が文の実行の一部として評価されるかどうか。
-
文内の独立した式同士の相対的な評価順序。
式の入れ子は、評価を完了するために満たす必要があるデータ依存関係を定義する。
すなわち、外側の式を評価する前に、入れ子になった式を評価しなければならない。
WGSL における式のオペランドの評価順序は左から右である。
たとえば、foo() + bar() では、bar() より前に
foo() を評価しなければならない。
§ 8 式を参照。
WGSL モジュール内の文は、制御フロー順に実行される。 § 9 文および§ 11.2 関数呼び出しを参照。
15.2. 一様性
集合操作 (たとえば、バリア、微分、または暗黙的に算出される微分に依存するテクスチャ操作)には、 GPU 上で同時に実行される異なる呼び出し間の協調が必要である。 すべての呼び出しがその操作を同時に、すなわち一様な制御フロー内で実行すると、 操作は正しく移植可能な形で実行される。
逆に、呼び出しの真部分集合が操作を実行する場合、すなわち非一様な制御フロー内では、 不正確または移植不可能な動作が発生する。 非形式的にいえば、非一様な制御依存関係の結果として、一部の呼び出しは集合操作へ到達するが、 ほかの呼び出しは到達しないか、同時には到達しない。 非一様な制御依存関係は、非一様な値に動作が依存する 制御フロー文から生じる。
たとえば、異なる呼び出しが 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回実行される。
注: 解析はスコープごとに1回実行されるものとして説明されているが、 実装は各スコープを含む単一の解析を実行してもよい。 ワークグループ一様性スコープと描画一様性スコープは、 異なるシェーダーステージに作用し、シェーダーステージ内の最大の一様性スコープを表すため、 実質的に同等である。
解析では、動的エラーが発生しないものと仮定する。 動的エラーを持つシェーダーステージは、 一様性解析の結果にかかわらず、すでに移植不可能である。
各関数は、次の2点を保証することを試みながら解析される。
-
ほかの関数を呼び出すときに一様性要件が満たされること。
-
その関数が呼び出されるときは常に一様性要件が満たされること。
この処理の一部として、解析はその関数に関するメタデータを算出し、 続いてその呼び出し元を解析するために役立てる。 これは、最初に呼び出しグラフを構築し、葉から上に向かって、 すなわち標準ライブラリー外の関数を呼び出さない関数からエントリーポイントに向かって、 関数を解析しなければならないことを意味する。 これにより、ある関数を解析するときには、そのすべての呼び出し先のメタデータが すでに算出されている。 この言語では再帰が禁止されているため、循環に陥る危険性はない。
注: 同じことを別の言い方で表すと、「(間接的な場合を含め)呼び出し先である」という 半順序によって関数をトポロジカルソートし、その順序で解析するということである。
さらに、各関数呼び出しについて、解析は、その呼び出しが一様な制御フロー内にあることを 証明できない場合に発生する発生規則の集合があれば、それを算出して伝播する。 これを呼び出しの潜在的発生集合という。 この集合の要素は、次の可能性から選ばれる。
-
微分の算出に依存する関数の場合、derivative_uniformity。
-
§ 17.12 サブグループ組み込み関数または§ 17.13 クアッド操作の関数の場合、subgroup_uniformity。
-
フィルタリングできない一様性要件の場合、名前のない発生規則。
-
これは、同期関数に依存する コンピュートシェーダー関数に使用される。
-
15.2.3. 関数の一様性要件の解析
各関数は2段階で解析される。
第1段階では、後続の小節の規則に基づいて、途中で有向グラフを構築しながら 関数の構文を走査する。 第2段階では、そのグラフを探索し、この関数を呼び出す際の制約を算出し、 場合によっては一様性失敗を発生させる。
-
プログラムの特定の位置は、一様な制御フロー内で 実行されなければならない。
-
式は一様な値でなければならない。
-
変数は一様な変数でなければならない。
-
ポインターを介してロードされ得る、メモリに格納された値は、一様な値でなければならない。
エッジは、その起点ノードに対応する文から終点ノードに対応する文への含意として理解できる。
たとえば、一様性要件の1つとして、workgroupBarrier 組み込み関数は、
一様な制御フロー内でのみ呼び出されなければならない。
これを表すため、RequiredToBeUniform.error から、
workgroupBarrier の呼び出し場所に対応するノードへの
エッジを追加する。
これを理解する1つの方法は、RequiredToBeUniform.error が命題 True に対応するため、
RequiredToBeUniform.error -> X は、
X が true であるということと同じだと考えることである。
逆に、あるものの一様性を保証できないこと (たとえばスレッド ID を保持する変数)を表すためには、対応するノードからMayBeNonUniform へのエッジを追加する。 これを理解する1つの方法は、MayBeNonUniform が命題 False に対応するため、 X -> MayBeNonUniform は、 X が false であるということと同じだと考えることである。
この解釈から、RequiredToBeUniform.error から到達可能な すべてのノードは、プログラムが有効となるために一様であることを要求されるものに対応し、 MayBeNonUniform へ到達可能なすべてのノードは、 一様性を保証できないものに対応することが導かれる。 したがって、RequiredToBeUniform.error からMayBeNonUniform への経路が存在する場合、 一様性違反があり、一様性失敗が発生する。
ノード RequiredToBeUniform.warning およびRequiredToBeUniform.info も同様に使用されるが、 代わりに警告または情報の診断を発生させる場合を決定するために役立つ。
-
RequiredToBeUniform.warning からMayBeNonUniform への経路がある場合、 警告の診断が発生する。
-
RequiredToBeUniform.info からMayBeNonUniform への経路がある場合、 情報の診断が発生する。
§ 2.3 診断で説明したように、より高い重大度の診断も 生成されている場合、より低い重大度の診断は破棄されることがある。
各関数について、2つのタグが算出される。
-
その関数の呼び出し場所に対する制御フローの一様性要件を記述する 呼び出し場所タグ。
-
一様性に対する関数の影響を記述する関数タグ。
関数の各仮パラメーターについて、1つまたは2つのタグが算出される。
-
パラメータータグは、パラメーター値の一様性要件を記述する。
-
パラメーター戻り値タグは、パラメーターの一様性が 関数の戻り値の一様性にどのように影響するかを記述する。
-
パラメーターの型がfunction アドレス空間を指すポインターである場合、 ポインターパラメータータグも算出される。 このタグは、関数呼び出しの実行中に、そのパラメーターが指すメモリ内の値が非一様になる可能性があるかどうかを記述する。
| 呼び出し場所タグ | 説明 |
|---|---|
| CallSiteRequiredToBeUniform.S, ここで S は重大度のerror、warning、またはinfo のいずれかである。 |
この関数は一様な制御フローからのみ呼び出さなければならない。
それ以外の場合、重大度 S の診断が発生する。
潜在的発生集合に関連付けられる。 |
| CallSiteNoRestriction | この関数は非一様な制御フローから呼び出すことができる。 |
| 関数タグ | 説明 |
|---|---|
| ReturnValueMayBeNonUniform | 関数の戻り値は非一様である可能性がある。 |
| NoRestriction | この関数は非一様性を導入しない。 |
| パラメータータグ | 説明 |
|---|---|
| ParameterRequiredToBeUniform.S, ここで S は重大度のerror、warning、またはinfo のいずれかである。 |
パラメーターは一様な値でなければならない。
パラメーター型がポインターである場合、その内容は必ずしも一様である必要はないが、
メモリビューは一様でなければならない。
それ以外の場合、重大度 S の診断が発生する。
潜在的発生集合に関連付けられる。 |
| ParameterContentsRequiredToBeUniform.S, ここで S は重大度のerror、warning、またはinfo のいずれかである。 |
ポインターパラメーターが指すメモリに格納された値は、一様な値でなければならない。
それ以外の場合、重大度 S の診断が発生する。
潜在的発生集合に関連付けられる。 |
| ParameterNoRestriction | パラメーター値には一様性要件がない。 |
| パラメーター戻り値タグ | 説明 |
|---|---|
| ParameterReturnContentsRequiredToBeUniform | 戻り値が一様な値となるためには、 パラメーターが一様な値でなければならない。 パラメーターがポインターである場合、そのポインターが指すメモリに格納された値も一様でなければならない。 |
| ParameterReturnNoRestriction | パラメーター値には一様性要件がない。 |
| ポインターパラメータータグ | 説明 |
|---|---|
| PointerParameterMayBeNonUniform | 関数呼び出しの後、ポインターパラメーターが指すメモリに格納された値は非一様である可能性がある。 |
| PointerParameterNoRestriction | ポインターパラメーターが指すメモリに格納された値の一様性は、 関数呼び出しの影響を受けない。 |
次のアルゴリズムは、特定の関数についてこれらのタグを算出する方法を説明する。
-
次のノードを作成する。
-
§ 15.2.4 ポインターの脱糖で説明するように、 ポインターを脱糖する。
-
function アドレス空間内のポインターである 各仮パラメーターについて、次のノードを作成する。
-
param_i_contents: これはメモリビューの内容の一様性を表す。
-
Value_return_i_contents: これは、メモリビューの内容の一様性に対する関数の影響を表す。
-
-
-
後続の各節(§ 15.2.5 関数スコープ変数の値解析、 § 15.2.6 文の一様性規則、§ 15.2.7 関数呼び出しの一様性規則、§ 15.2.8 式の一様性規則)の規則に従って、 グラフにノードとエッジを追加しながら関数の構文を走査する。 関数本体の開始制御フローには、CF_start を使用する。
-
このステップで追加されるノードを内部ノードという。
-
-
次のように初期化する。
-
関数タグをNoRestriction に初期化する。
-
呼び出し場所タグをCallSiteNoRestriction に初期化する。
-
各param_i のパラメータータグをParameterNoRestriction に初期化する。
-
各param_i のパラメーター戻り値タグをParameterReturnNoRestriction に初期化する。
-
各param_i のポインターパラメータータグが存在する場合、 PointerParameterNoRestriction に初期化する。
-
-
{error、warning、info} の順序で各重大度 S について、 次を実行する。
-
R.S を、RequiredToBeUniform.S から到達可能な 未訪問ノードの集合とする。
-
R.S 内の内部ノードを 訪問済みとしてマークする。
-
PTS を、RequiredToBeUniform.S に関連付けられた潜在的発生集合とする。
-
R.S がノード MayBeNonUniform を含む場合、一様性失敗を発生させる。
-
PTS 内の各 t について、重大度 S と 発生規則 t を持つ診断を発生させる。
-
-
それ以外の場合、次を行う。
-
R.S がCF_start を含み、 呼び出し場所タグが初期化後に 更新されていない場合、その呼び出し場所タグをCallSiteRequiredToBeUniform.S に設定し、その潜在的発生集合を PTS に設定する。
-
R.S 内の各param_i について、 対応するパラメータータグが初期化後に 更新されていない場合、そのタグをParameterRequiredToBeUniform.S に設定し、その潜在的発生集合を PTS に設定する。
-
R.S 内の各param_i_contents について、 対応するパラメータータグが初期化後に 更新されていない場合、そのタグをParameterContentsRequiredToBeUniform.S に設定し、その潜在的発生集合を 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. ポインターの脱糖
function アドレス空間にあるポインター型の各パラメーターは、 パラメーターを参照外ししたものと等価な初期値を持つローカル変数宣言として脱糖される。 すなわち、function アドレス空間のポインターはローカル変数宣言へのエイリアスとみなされる。 初期値の代入により、i番目のパラメーターの param_i_contents への辺が生成される (すなわち、V(e) は param_i_contents である)。
実効値型がポインター型である各let 宣言 L は、次のように脱糖される:
-
L の初期化式の各部分式 SE を、後行順の深さ優先走査で訪問する:
-
更新されている可能性のある L の初期化式を記録する。
この脱糖は、ポインターの各使用箇所でルート識別子を直接露出させることで、 後続の解析を単純化する。
注: 一様性解析の目的上、型検査は、 この脱糖が行われる前と後の両方で実施されるものとして記述される。
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. 関数スコープ変数の値解析
特定の文における各関数スコープ変数の値は、 そこに到達する代入、および場合によってはその初期値の観点から解析できる。
次の場合、代入は完全代入である:
それ以外の場合、代入は部分代入である。
完全参照とは、 次のいずれかである参照型の式である:
完全ポインターとは、 次のいずれかであるポインター型の式である:
注: この解析の目的上、 ポインター型の形式パラメーターが完全ポインターになり得る場合は必要ない。
完全参照と、 同様に完全ポインターは、 対応する起点変数 x のすべてのメモリ位置に対するメモリビューである。
完全参照でない参照は、 部分参照である。 したがって、部分参照は次のいずれかである:
単一のメンバーを持つ構造体型と、その型を格納する変数を考える:
struct S { member : i32; } fn foo () { var v : S ; }
この場合、v は完全参照であり、v.member は部分参照である。
それらのメモリビューは同じメモリ位置を包含するが、v の格納型は S であり、
v.s の格納型は i32 である。
単一の要素を持つ配列でも同様の状況が発生する:
fn foo () { var arr : array< i32, 1 > ; }
この場合、arr は完全参照であり、arr[0] は部分参照である。
それらのメモリビューは同じメモリ位置を包含するが、arr の格納型は
array<i32,1> であり、arr[0] の格納型は i32 である。
解析を単純化するため、任意の種類の部分参照を介した代入は、 関連する起点変数内のすべてのメモリ位置を変更するものではないとして扱われる。 これにより解析は保守的になり、厳密に必要な場合よりも多くのプログラムで一様性失敗が発生する可能性がある。
完全スウィズルビューとは、 次を満たすスウィズルビュー sv = (p, IndexList) に評価される式である:
-
p は N 個の要素を持つベクトルへの完全ポインターである。
-
IndexList は {0, ..., N-1} の置換である。
注: 完全スウィズルビューを介して代入すると、 メモリ内の基礎となるベクトルのすべての要素が上書きされる。
部分スウィズルビューとは、 完全スウィズルビューではないスウィズルビュー型の式である。
注: 完全スウィズルビューであるかどうかは、 基礎となるポインター式の完全性と IndexList のみに依存し、 その両方がシェーダー作成時に既知であるため、シェーダー作成時に判定できる。 これはスウィズルビュー式を連鎖させる場合にも成り立つ。
完全参照または完全スウィズルビューを介した代入は、完全代入である。
部分参照または部分スウィズルビューを介した代入は、部分代入である。
後続の節の一様性規則が、RHSValue として使用される関数スコープ変数の値を参照する場合、 それは RHSValue 式を評価する前の変数の値を意味する。 後続の節の一様性規則が、LHSValue として使用される関数スコープ変数の値を参照する場合、 それはその式が現れる文を実行した後の変数の値を意味する。
制御フロー文または部分代入により、 変数の使用箇所にその変数への複数の代入が到達する場合がある。 解析は、各制御フロー出口に到達する代入の集合の和集合を取ることで、 制御フロー文から到達する複数の代入を結合する。
次の表は、代入を結合する規則を説明する。
一様性グラフでは、各結合は結果ノードから値の供給元を表すノードへの辺である。
これは任意の変数 x を用いて記述される。次の表記を使用する:
-
Vin(S) は、文 S の実行前の
xの値である。 -
Vout(S) は、文 S の実行後の
xの値である。 -
Vout(prev) は、現在の文の実行前の
xの値である。 -
Vin(next) は、次の文の実行前の
xの値である。 -
V(e) は、後続の節における式の値ノードである。
-
V(0) は、
xの実効値型のゼロ値である。
| 文 | 結果 | 結果からの辺 |
|---|---|---|
| var x; | Vin(next) | V(0) |
|
var x = e; | Vin(next) |
V(e)
注: これは x への完全代入である。 |
|
x = e; | ||
|
r = e; ここで r は変数 x への完全参照である | ||
|
sv = e; ここで sv は起点変数 x を持つ完全スウィズルビューである | ||
|
r = e; ここで r は変数 x への部分参照である | Vout(S) |
V(e), Vout(prev)
注: これは x への部分代入である。 注: 部分代入には以前の値が含まれる。 代入が書き込むのは格納された成分の一部だけであるか、書き込まれる値の型が起点変数の格納型と異なる。 |
|
sv = e; ここで sv は起点変数 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), s1 の振る舞いが {Next,Continue} と交差する場合は Vout(s2) |
| loop { s1 continuing { s2 } } | Vin(s2) | Next が s1 の振る舞いに含まれる場合は Vout(s1), 振る舞いが {Continue} であり、制御を s2 に移す s1 内の すべての si について Vout(si) |
| loop { s1 continuing { s2 } } | Vin(next) | Break が s1 の振る舞いに含まれる場合は Vout(s2), 振る舞いが {Break} であり、制御を next に移す s1 内の すべての si について Vout(si) |
| switch e { case _: s1 case _: s2 ... case _: s3 } | Vin(si) | Vout(prev) |
| switch e { case _: s1 case _: s2 ... case _: s3 } | Vin(next) | 振る舞いに Next または Break が含まれるすべての
si について Vout(si), および、振る舞いが {Break} であり、制御を next に移す sj 内のすべての文について Vout(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 と表記する。
値の一様性に対応するノードを計算する代わりに、代入先の変数の一様性に対応するノードを計算する。
注: LHSValue には、インクリメント文および デクリメント文の式が含まれる。
注: RHSValue には、代入文の右辺の一部である式、または 代入文、インクリメント文、デクリメント文の いずれにも含まれない式が含まれる。
複数の辺を作成する必要がある場合、X -> Y, X -> Z の略記として
X -> {Y, 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 文を参照) -
whileループは脱糖される(§ 9.4.5 While 文を参照) -
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 への辺を追加する
-
呼び出し場所タグの潜在的発生集合のメンバーを、 RequiredToBeUniform.S に関連付けられた 潜在的発生集合に追加する。
-
-
関数タグがReturnValueMayBeNonUniform である場合、 Result からMayBeNonUniform への辺を追加する
-
各引数 i について:
-
対応するパラメータータグがParameterRequiredToBeUniform.S である場合:
-
RequiredToBeUniform.S からarg_i への辺を追加する。
-
パラメータータグの潜在的発生集合のメンバーを、 RequiredToBeUniform.S に関連付けられた 潜在的発生集合に追加する。
-
-
パラメーター戻りタグが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 同期組み込み関数に含まれる関数の呼び出し:
-
関数タグ NoRestriction を持つ。
-
次の呼び出し場所タグを持つ:
-
subgroup_uniformity がサポートされていないか、一様性スコープが subgroup でない場合は、 名前のない発生規則からなる潜在的発生集合を持つ CallSiteRequiredToBeUniform.error。
-
注: この発生規則には 名前がないため、フィルター処理できない。
-
-
それ以外の場合はCallSiteNoRestriction。
-
-
さらに、subgroup_uniformity が サポートされていないか、一様性スコープが subgroup でない場合、 workgroupUniformLoad の呼び出しでは、 パラメーター
pは、名前のない発生規則からなる潜在的発生集合を持つパラメータータグ ParameterRequiredToBeUniform.error を持つ。
-
-
§ 17.6 微分組み込み関数、§ 17.7.8 textureSample、§ 17.7.9 textureSampleBias、および§ 17.7.10 textureSampleCompare に含まれる関数の呼び出し:
-
次のような呼び出し場所タグを持つ:
-
subgroup_uniformity がサポートされていないか、一様性スコープが subgroup でない場合
-
DF を、呼び出し場所の位置および発生規則derivative_uniformity に対する最も近くの外側にある診断フィルターとする
-
DF が存在する場合、S を DF の新しい重大度パラメーターとする。
-
S が重大度off である場合、 呼び出し場所タグはCallSiteNoRestriction である。
-
それ以外の場合、呼び出し場所タグは、derivative_uniformity 要素からなる潜在的発生集合を持つ CallSiteRequiredToBeUniform.S である。
-
-
そのような DF が存在しない場合、 呼び出し場所タグは、derivative_uniformity 要素からなる潜在的発生集合を持つ CallSiteRequiredToBeUniform.error である。
-
-
それ以外の場合はCallSiteNoRestriction。
-
-
§ 17.7.4 textureLoad の呼び出し:
-
次のような関数タグを持つ:
-
tパラメーターに対応する引数が読み書き可能なストレージテクスチャ である場合はReturnValueMayBeNonUniform -
それ以外の場合はNoRestriction
-
-
§ 17.12 サブグループ組み込み関数または§ 17.13 クアッド演算に含まれる関数の呼び出し:
-
次の関数タグを持つ:
-
一様性スコープが subgroup であり、 関数が次のいずれかである場合はNoRestriction:
-
それ以外の場合はReturnValueMayBeNonUniform
-
-
DF を、呼び出し場所の位置および発生規則subgroup_uniformity に対する最も近くの外側にある診断フィルターとする
-
次のような呼び出し場所タグを持つ:
-
subgroup_uniformity がサポートされていないか、一様性スコープが subgroup である場合:
-
DF が存在する場合、S を DF の新しい重大度パラメーターとする。
-
S が重大度off である場合、 呼び出し場所タグはCallSiteNoRestriction である。
-
それ以外の場合、呼び出し場所タグは、subgroup_uniformity 要素からなる潜在的発生集合を持つ CallSiteRequiredToBeUniform.S である。
-
-
そのような DF が存在しない場合、 呼び出し場所タグは、subgroup_uniformity 要素からなる潜在的発生集合を持つ CallSiteRequiredToBeUniform.error である。
-
-
それ以外の場合はCallSiteNoRestriction。
-
-
さらに、subgroupShuffleUp またはsubgroupShuffleDown の呼び出しの場合、 パラメーター
deltaは次のパラメータータグを持つ:-
subgroup_uniformity がサポートされていないか、一様性スコープが subgroup である場合:
-
DF が存在する場合、S を DF の新しい重大度パラメーターとする。
-
S が重大度off である場合、 パラメータータグはNoRestriction である。
-
それ以外の場合、パラメータータグは、subgroup_uniformity 要素からなる潜在的発生集合を持つ ParameterRequiredToBeUniform.S である。
-
-
そのような DF が存在しない場合、 パラメータータグは、subgroup_uniformity 要素からなる潜在的発生集合を持つ ParameterRequiredToBeUniform.error である。
-
-
それ以外の場合はNoRestriction。
-
-
さらに、subgroupShuffleXor の呼び出しの場合、 パラメーター
maskは次のパラメータータグを持つ:-
subgroup_uniformity がサポートされていないか、一様性スコープが subgroup である場合:
-
DF が存在する場合、S を DF の新しい重大度パラメーターとする。
-
S が重大度off である場合、 パラメータータグはNoRestriction である。
-
それ以外の場合、パラメータータグは、subgroup_uniformity 要素からなる潜在的発生集合を持つ ParameterRequiredToBeUniform.S である。
-
-
そのような DF が存在しない場合、 パラメータータグは、subgroup_uniformity 要素からなる潜在的発生集合を持つ ParameterRequiredToBeUniform.error である。
-
-
それ以外の場合はNoRestriction。
-
-
注: WGSL 実装は、関数呼び出し前の制御フローが 特定のスコープについて一様である場合、 関数呼び出し後も一様であることを保証する。
15.2.8. 式の一様性規則
式を解析する規則は、式自体とその開始時点の制御フローに対応するノード (以下では「CF」と記す)の両方を引数として受け取り、次のものを返す:
-
その値に対応するノード
-
グラフに追加する新しいノードと辺の集合
| 式 | 新しいノード | 再帰的解析 | 結果の値ノード | 新しい辺 |
|---|---|---|---|---|
| e1 || e2 | (CF, e1) => V1 (V1, e2) => V2 | V2 | ||
| e1 && e2 | ||||
| リテラル | CF | |||
| 関数スコープ変数 "x" に解決される識別子であり、 その識別子がメモリビュー式 MVE のルート識別子として現れ、 型検査中に MVE に対してロード規則が呼び出される場合 | Result | X は、この式を含む文への入力時点における "x" の値に対応するノードである | Result |
Result -> {CF, X}
注: X は "x" の
Vout(prev) と等価である |
| 関数スコープ変数 "x" に解決される識別子であり、 その識別子がスウィズルビュー式 SVE のルート識別子として現れ、 型検査中に SVE に対してスウィズルビューのロード規則が呼び出される場合 | ||||
| 関数スコープ変数 "x" に解決される識別子であり、 "x" が脱糖されたポインターパラメーター i であり、 その識別子がメモリビュー式 MVE のルート識別子として現れ、 型検査中に MVE に対してロード規則が呼び出されない場合 | param_i | |||
| 関数スコープ変数 "x" に解決される識別子であり、 "x" が脱糖されたポインターパラメーター i であり、 その識別子がスウィズルビュー式 SVE のルート識別子として現れ、 型検査中に SVE に対してスウィズルビューのロード規則が呼び出される場合 | ||||
| 関数スコープ変数 "x" に解決される識別子であり、 その識別子がメモリビュー式 MVE のルート識別子として現れ、 型検査中に MVE に対してロード規則が呼び出されない場合 | CF | |||
| 関数スコープ変数 "x" に解決される識別子であり、 その識別子がスウィズルビュー式 SVE のルート識別子として現れ、 型検査中に SVE に対してスウィズルビューのロード規則が呼び出されない場合 | ||||
| const 宣言、override 宣言、 let 宣言、または非ポインター型の非組み込み形式パラメーター "x" に解決される識別子 | Result | X は "x" に対応するノードである | Result | Result -> {CF, X} |
| 非読み取り専用のアクセスモードを持つ storage、workgroup、 またはprivate アドレス空間にあるポインター型の形式パラメーターに解決される識別子であり、 その識別子がメモリビュー式 MVE のルート識別子として現れ、 型検査中に MVE に対してロード規則が呼び出される場合 | MayBeNonUniform | |||
| 非読み取り専用のアクセスモードを持つ storage、workgroup、 またはprivate アドレス空間にあるポインター型の形式パラメーターに解決される識別子であり、 その識別子がスウィズルビュー式 SVE のルート識別子として現れ、 型検査中に SVE に対してスウィズルビューのロード規則が呼び出される場合 | ||||
| 非読み取り専用のアクセスモードを持つ storage、workgroup、 またはprivate アドレス空間にあるポインター型の形式パラメーターに解決される識別子であり、 その識別子がメモリビュー式 MVE のルート識別子として現れ、 型検査中に MVE に対してロード規則が呼び出されない場合 | CF | |||
| 非読み取り専用のアクセスモードを持つ storage、workgroup、 またはprivate アドレス空間にあるポインター型の形式パラメーターに解決される識別子であり、 その識別子がスウィズルビュー式 SVE のルート識別子として現れ、 型検査中に SVE に対してスウィズルビューのロード規則が呼び出されない場合 | ||||
| function 以外のアドレス空間にあり、 読み取り専用のアクセスモードを持つポインター型の形式パラメーターに解決される識別子 | CF | |||
| 一様な組み込み値 "x" に解決される識別子 | CF | |||
| 非一様な組み込み値 "x" に解決される識別子 | MayBeNonUniform | |||
| 読み取り専用のモジュールスコープ変数 "x" に解決される識別子 | CF | |||
| 非読み取り専用のモジュールスコープ変数 "x" に解決される識別子であり、 その識別子がメモリビュー式 MVE のルート識別子として現れ、 型検査中に MVE に対してロード規則が呼び出される場合 | MayBeNonUniform | |||
| 非読み取り専用のモジュールスコープ変数 "x" に解決される識別子であり、 その識別子がスウィズルビュー式 SVE のルート識別子として現れ、 型検査中に SVE に対してスウィズルビューのロード規則が呼び出される場合 | ||||
| 非読み取り専用のモジュールスコープ変数 "x" に解決される識別子であり、 その識別子がメモリビュー式 MVE のルート識別子として現れ、 型検査中に MVE に対してロード規則が呼び出されない場合 | CF | |||
| 非読み取り専用のモジュールスコープ変数 "x" に解決される識別子であり、 その識別子がスウィズルビュー式 SVE のルート識別子として現れ、 型検査中に SVE に対してスウィズルビューのロード規則が呼び出されない場合 | ||||
| ( e ) | (CF, e) => V | V | ||
| op e, ここで op は単項演算子である | ||||
| e.field, ここで field は構造体メンバー名である | ||||
| e.swiz, ここで swiz はスウィズル名である | ||||
| 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 |
次の組み込み入力変数は一様であるとみなされる:
サブグループ一様性スコープでは、 次の組み込み入力変数も一様であるとみなされる:
それ以外のすべてのもの(組み込み値を参照)は非一様であるとみなされる。
注: 解析では複合型の成分を個別に解析しないため、 作者は一様な組み込み値を他の非一様な入力とまとめることを避けるべきである。
| 式 | 新しいノード | 再帰的解析 | 結果の変数ノード | 新しい辺 |
|---|---|---|---|---|
| 関数スコープ変数 "x" に解決される識別子 | Result | X は、この式を含む文の出力時点における "x" の値に対応するノードである。 | Result |
Result -> {CF, X}
注: X は "x" の
Vin(next) と等価である |
| const 宣言、override 宣言、 let 宣言、または形式パラメーター "x" に解決される識別子 | X は "x" に対応するノードである | X | ||
| モジュールスコープ変数 "x" に解決される識別子 | MayBeNonUniform | |||
| e.field, ここで field は構造体メンバー名である | LHSValue: (CF, e) => L1 | L1 | ||
| e.swiz, ここで swiz はスウィズル名である | ||||
| *e | ||||
| &e | ||||
| e2[e1] | (CF, e1) => V1 LHSValue: (CF, e2) => L2 | L2 | L2 -> V1 | |
f()引数のない関数呼び出し式 | 関数呼び出し解析を呼び出す: LHSValue: (CF, f()) => Result | Result | ||
f(e1,...,eN)引数を持つ関数呼び出し式 | 関数呼び出し解析を呼び出す: LHSValue: (CF, f(e1,...,eN)) => Result | Result |
15.2.9. 制御フロー内のすべての地点に対する一様性の注釈
この小節全体は非規範的である。
実装者が、シェーダー全体の制御フロー内の各地点について一様であるかどうか (したがって、その地点で一様性を必要とする関数を呼び出すことが妥当かどうか)を示す 診断モードを開発者に提供する場合、次の方法を推奨する:
-
各関数のグラフを保持しながら、前の小節で説明した(必須かつ規範的な)解析を実行する。
-
それらすべてのグラフのすべての辺を反転する
-
エントリーポイントから開始し、ある関数のすべての呼び出し元を訪問する前には その関数を決して訪問しないように、各関数を処理する:
-
MayBeNonUniform から、 少なくとも 1 つの呼び出し元で非一様だったすべての引数への辺を追加する。
-
関数が少なくとも 1 つの呼び出し元で非一様な制御フロー内から呼び出された場合、 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 文の条件が一様な値であった場合
(たとえば、各呼び出しがユニフォームバッファから同じ値を読み取る場合)も、
プログラムは妥当だった。
15.2.10.2. 関数スコープ変数の一様性
この例は、関数スコープ変数の値に依存する、妥当なバリア関数呼び出しと無効なバリア関数呼び出しの両方を示す。
x の値は可変なモジュールスコープ変数 a から導出されるため、
workgroupBarrier は無効である。
x の値は不変なモジュールスコープ変数 b から導出されるため、
storageBarrier は妥当である。
この例は、関数スコープ変数の生存期間における異なる一様性の期間を分離できるという、
値解析の能力を強調している。
また、この例は、最初の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 { // 無効なバリア関数呼び出し。 workgroupBarrier (); } x = b ; if x < 0 { // 妥当なバリア関数呼び出し。 storageBarrier (); } }
注: サブグラフは、理解しやすくするためにのみ この例へ含められている。
15.2.10.3. 複合値解析の制限
一様性解析の制限の 1 つは、複合値の成分を個別に追跡しないことである。 すなわち、非一様な成分値が 1 つでもあれば、解析は複合値全体を非一様として扱う。 この例は、この問題と、この制限を回避するためにシェーダー作者が利用できる回避策を示す。
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 { // 妥当なバリア関数呼び出し。 workgroupBarrier (); } }
15.2.10.4. ループ内の一様性
この例では、ループ内に無効な workgroupBarrier 関数呼び出しが存在する。
非一様な組み込み値 local_invocation_index は、
ループ内でバリアより後に現れるにもかかわらず、最終的な原因となっている。
これは後の反復で、ワークグループ内の一部の呼び出しが早期にループを終了する一方、
他の呼び出しはバリアの実行を試みるために発生する。
解析は、ループ本体の開始時点の制御(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 の両方のパラメーターのパラメーター戻りタグを
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 は、0 ≤ L(I) < W を満たす一意のローカル呼び出しインデックス L(I) を持ち、 その範囲全体が包含されることに注意。
コンピュートシェーダーの実行は、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で識別される 1 つのワークグループに対応する:
( ⌊ CSi ÷ workgroup_size_x ⌋, ⌊ CSj ÷ workgroup_size_y ⌋, ⌊ CSk ÷ workgroup_size_z ⌋)
また、次のローカル呼び出し IDで識別される、 そのワークグループ内の 1 つの呼び出しにも対応する:
( 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 つ作成する。 グラフィックスプリミティブの端などでは、クアッドを完全に埋めるのに十分な RasterizationPoint が存在しない場合がある。 クアッド内で RasterizationPoint に対応する呼び出しが 1、2、または 3 個だけの場合、 フラグメント処理はクアッド内の埋められていない各位置について、 ヘルパー呼び出しを作成する。
ヘルパー呼び出しの観測可能な効果は限定されている。 ヘルパー呼び出しは微分の計算を支援し、 サブグループ演算に参加する場合がある。 したがって、ヘルパー呼び出しには次の制限が適用される:
-
storage またはhandle アドレス空間に対する書き込みアクセスは実行されない (§ 14.5.1 メモリ操作も参照)。
-
アトミック組み込み関数は、 不定な結果を返す。
-
エントリーポイントの戻り値は、 GPURenderPipeline の下流でそれ以上処理されない。
クアッド内のすべての呼び出しがヘルパー呼び出しになった場合 (たとえば、discard 文の実行による場合)、 クアッドの実行は終了されることがある。 ただし、そのような終了は非一様な制御フローを生成するとはみなされない。
15.5. サブグループ
サブグループとは、 コンピュートまたはフラグメントシェーダーステージのエントリーポイントを並行して実行し、 データを効率的に共有して結果を集合的に計算できる呼び出しの集合である。 コンピュートシェーダーまたはフラグメントシェーダー内の各呼び出しは、 ちょうど 1 つのサブグループに属する。 コンピュートシェーダーでは、各サブグループは特定のワークグループの部分集合である。 フラグメントシェーダーでは、サブグループに複数の描画コマンドからの呼び出しが含まれる場合がある。 各クアッドは 1 つのサブグループ内に包含される。
サブグループサイズとは、 サブグループ内の呼び出しの最大数である。 シェーダー内では、subgroup_size 組み込み値を介してこの値へアクセスできる。 サブグループサイズはディスパッチコマンド内、 したがってワークグループ内では一様な値であるが、 描画コマンド内では一様な値でない場合がある。 すべてのサブグループサイズは [4, 128] の範囲内の 2 の累乗であり、 特定のデバイス向けにコンパイルされたシェーダーの値は、 WebGPU § 4.3 GPUAdapter の [subgroupMinSize, subgroupMaxSize] の範囲内になる。 実際のサイズは、シェーダー、デバイスのプロパティ、およびデバイスコンパイラーに依存する。 各デバイスは、使用可能なサブグループサイズの範囲の部分集合 (単一の値である場合もある)をサポートする。 デバイスコンパイラーは、さまざまなヒューリスティックを使用して、 サポートされているサイズから 1 つを選択する。 各サブグループに含まれる呼び出しは、報告されたサブグループサイズより少ない場合がある (たとえば、起動された呼び出しがサブグループサイズより少ない場合)。
呼び出しのサブグループ呼び出し
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 の間には、
定義された関係は存在しない。
移植性のないコードを避けるため、シェーダー作者はこれら 2 つの値の間に
特定の対応関係があると仮定するべきではない。
同じサブグループ内の呼び出しが異なる制御フロー経路を実行するとき、 サブグループの実行が分岐したという。 これは非一様な制御フローの特殊な場合である。 分岐はサブグループ演算の意味論に影響する。 サブグループ演算を並行して実行するサブグループ内の呼び出しは、 その演算についてアクティブである。 サブグループ内のその他の呼び出しは、その演算について非アクティブである。 サブグループサイズがサブグループ内の呼び出し数を超える場合、 追加の仮想的な呼び出しは非アクティブであるとみなされる。 ヘルパー呼び出しは、 演算でアクティブまたは非アクティブになる場合がある。 すなわち、一部のデバイスではヘルパー呼び出しがサブグループ演算に参加することがあるが、 他のデバイスでは参加しないことがある。
注: 非一様な制御フロー内で動作する際、 基礎となるデバイス間には相当な移植性の違いがあり、 デバイスコンパイラーはそのようなコードを積極的に最適化することが多い。 その結果、サブグループに含まれるアクティブな呼び出しの集合が、 シェーダー作者の予想と異なる場合がある。
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)演算である。
サブグループ内のアクティブな呼び出しは、 結果を決定するために通信する。 したがって、すべての呼び出しがアクティブなとき (すなわち、サブグループレベルの一様な制御フロー内) にこれらの関数を呼び出すと、移植性が最大化される。
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 より下にある最大の浮動小数点値のいずれかである。 丸めモードによって、どちらを選択するかが決定される。
一般に、NaN 入力を持つ演算は、 NaN 出力を生成する。 例外には次のものが含まれる:
-
NaN は、他のどの浮動小数点値とも等しくなく、それより小さくも大きくもない。 そのような比較は false を生成する。
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 関数は、 通常の乗算(丸めステップを含む)と加算(さらに別の丸めステップを含む)に展開される場合があるが、 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 が T の有限範囲内にある場合、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 は丸めモードを指定しない。
注: 浮動小数点型には正および負の無限大が含まれるため、 正しく丸められた結果は有限または無限大になる場合がある。
注: 無制限の精度で計算された演算の結果には、
double の精度を超える精度が必要になる場合がある。
そのような場合の例は、x=1.0 かつ y=1.17e-38
(最小の正の正規単精度浮動小数点数)である x - y である。
これらの数の指数は 126 単位離れている。IEEE-754 のbinary64(倍精度)形式は仮数部に 52 ビットしかないため、
減算を行うと y のすべての有効ビットが失われる。
丸めモードによっては、この場合や y が小さいもののゼロではない他の多くの場合に、
WGSL 式 x - y が x と同じ値を生成することがある。
[ECMASCRIPT] は、IEEE-754 の
roundTiesToEven 丸めモードに相当するものを使用することに注意。
浮動小数点数 x の最下位桁単位、
ULP は、
次のように定義される[Muller2005]:
-
xが浮動小数点型の有限範囲内にある場合、ULP(x) は、a≤x≤bを満たす、等しくない 2 つの有限浮動小数点数aとbの間の最小距離である (すなわち、ulp(x) = mina,b|b - a|)。 -
それ以外の場合、ULP(x) は
|b - a|である。 ここでbとaは、表現可能な有限浮動小数点値のうち、 それぞれ最大値と 2 番目に大きい値である。
演算の精度は、次の 5 つの可能性のいずれかとして示される:
-
正しい結果(浮動小数点以外の結果値の場合)。
-
正しく丸められた結果。
-
絶対誤差の上限。
-
ULP として表される相対誤差の上限。
-
精度の継承元となる式。 すなわち、演算の精度は、指定された WGSL 式を評価する精度として定義される。 指定された式は、その関数の妥当な実装の 1 つにすぎない。
継承元の式を評価する場合、部分式の評価には、丸め、 オーバーフロー、 再結合、 融合、 およびゼロへのフラッシュに関するものを含む、 浮動小数点評価のその他の規則が適用される。
WebGPU 実装は、より高い精度または極端な入力に対するより大きな許容度を持つ 別の方法で演算を実装できる。
演算の精度が入力範囲について指定されている場合、 その範囲外の入力値に対する精度は未定義である。
許容される結果が結果型の有限範囲外にある場合、 § 15.7.3 浮動小数点の丸めとオーバーフロー の規則が適用される。
15.7.4.1. 具象浮動小数点式の精度
| 式 | f32 の精度 | f16 の精度 |
|---|---|---|
x + y
| 正しく丸められる | |
x - y
| 正しく丸められる | |
x * y
| 正しく丸められる | |
x / y
| |y| が [2-126, 2126] の範囲内にある場合は 2.5 ULP
| |y| が [2-14, 214] の範囲内にある場合は 2.5 ULP
|
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)
|
i ≠ j である場合の
(x[i] * y[j] - x[j] * y[i]) から継承
| |
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-21。x が区間 [0.5, 2.0] 外にある場合は 3 ULP。 | x が区間 [0.5, 2.0] 内にある場合、絶対誤差は最大 2-7。x が区間 [0.5, 2.0] 外にある場合は 3 ULP。 |
log2(x)
| x が区間 [0.5, 2.0] 内にある場合、絶対誤差は最大 2-21。x が区間 [0.5, 2.0] 外にある場合は 3 ULP。 | x が区間 [0.5, 2.0] 内にある場合、絶対誤差は最大 2-7。x が区間 [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 | 該当なし |
unpack4x8unorm(x)
| 3 ULP | 該当なし |
unpack2x16snorm(x)
| 3 ULP | 該当なし |
unpack2x16unorm(x)
| 3 ULP | 該当なし |
unpack2x16float(x)
| 正しく丸められる | 該当なし |
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 は多くの浮動小数点演算を実装による近似として指定している。 実装には理想値へ近づけるよう努めることが推奨されるが、 厳密な要件は指定されていない。
-
AbstractFloat 値のULP は、AbstractFloat が IEEE-754 のbinary64 型と同一であると仮定する。
binary64 形式の仮数部は f32 型の仮数部より 29 ビット長いため、 f32 値の 1 ULP は、 IEEE-754 binary64 値の 1 ULP より 229 倍大きい。
たとえば、演算の真の結果値が x であるものの、 x' として計算されたとする。 その誤差 x-x' が f32 で 3 ULP である場合、 同じ絶対誤差 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 を発生させる場合がある。
実装は演算を再結合できる。
変換後の式が元の形式と同等以上の精度を持つ場合、実装は演算を融合できる。 たとえば、一部の融合積和演算の実装は、乗算の後に加算を行うより正確になる場合がある。
15.7.6. 浮動小数点変換
この節では、変換元または変換先のいずれかが浮動小数点型であるスカラー変換の詳細を説明する。
この節では、浮動小数点型は次のいずれかである:
-
WGSL のf32、 f16、およびAbstractFloat 型。
-
浮動小数点規格IEEE-754 が定義する 二進形式に対応する仮想的な型。
注: WGSL のf32 型は IEEE-754 のbinary32 形式に対応し、 WGSL のf16 型は IEEE-754 のbinary16 形式に対応することを思い出されたい。
スカラー浮動小数点から整数への変換 アルゴリズムは次のとおりである:
浮動小数点スカラー値 X を整数スカラー型 T へ変換するには:
注: 言い換えると、NaN でない場合、 浮動小数点から整数への変換は値を対象型の範囲内にクランプし、その後ゼロ方向へ丸める。 このクランプ要件は、WGSL が意味のある結果を必須とする一方、 C および C++ では未定義動作となり、IEEE-754 では 無効な演算例外と NaN の結果が必須となる箇所の 1 つである。
数値スカラーから浮動小数点への変換 アルゴリズムは次のとおりである:
アルゴリズム: 浮動小数点への数値スカラー変換入力:
X、型 S の数値スカラー値
T、変換先の浮動小数点型。
出力: XOut、X を型 T へ変換した結果。 またはエラーを生成する。
手順:
X が変換元の型 S の NaN である場合、 XOut は型 T の NaN である。
X が変換先の型 T で正確に表現可能である場合、 XOut は X と等しい T 内の値である。
それ以外の場合、X は T で正確に表現できない:
X が T 内の隣接する 2 つの有限値の間にある場合、 XOut はその 2 つの値のいずれかである。 WGSL は表現可能な上側または下側のどちらの値を選択するかを指定せず、 そのような変換の異なる実行では異なる値を選択する場合がある。
それ以外の場合、X は変換先の型の有限範囲外にある:
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.8 算術式および§ 17.5 数値組み込み関数は、 それぞれ浮動小数点式および組み込み関数の定義域を定義している。 特定の演算に制限が記載されていない場合、その定義域は全域である。 すなわち、定義域にはすべての有限および無限大の入力が含まれる。 それ以外の場合、明示的な定義域が記載される。
WGSL 演算がIEEE-754 によって定義された演算に
対応する多くの場合、両者は同じ定義域を持つ。
たとえば、WGSL と IEEE-754 の acos 演算は、どちらも定義域 [−1,1] を持つ。
明示的に記載された定義域を持つ成分ごとの WGSL 演算では、 スカラーの場合だけが説明される。ベクトルの場合は成分ごとの意味論から推論される。
一部の WGSL 演算は、他の WGSL 式によって実装される場合がある。 § 15.7.4 浮動小数点の精度では、 これらを継承された精度を持つものとして記載している。 これらの演算の定義域を記載する場合、次のいずれかとなる:
-
定義域が明示的に説明される、または
-
定義域が線形項から暗示されると記載され、 次の方法で導出される:
-
元の演算が、浮動小数点の加算、減算、および乗算演算の組み合わせである 「継承元」の式で置換されたと仮定する。
-
指定されたパラメーターに対するそれらの残りの演算の定義域制限を適用し、組み合わせる。
-
例: 2 要素ベクトル a および b に対する
dot(a,b) 関数の精度は、式
a[0] * b[0] + a[1] * b[1]
から継承される。
これは、2 つの浮動小数点乗算と 1 つの浮動小数点加算を使用する。
-
浮動小数点乗算は、一方のオペランドがゼロで他方が無限大である場合を除き、 拡張実数全体にわたって適切に定義される。
-
浮動小数点加算は、2 つのオペランドが反対の符号を持つ無限大である場合を除き、 適切に定義される。
-
したがって、定義域は、次の場合を除く、拡張実数の 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> () // 2 つの f32 成分からなるゼロ値ベクトル。 vec2< f32> ( 0.0 , 0.0 ) // 同じ値を明示的に記述したもの。 vec3< i32> () // 3 つの i32 成分からなるゼロ値ベクトル。 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 はスカラー
|
| 説明 | 成分ごとに
4 成分のベクトルを、e1、v1.x、v1.y、
および v1.zを成分として構築する。
|
| オーバーロード |
|
| パラメーター化 | T は AbstractInt
|
| 説明 | 値 vec4(0,0,0,0) を返す。
|
17.2. ビット再解釈組み込み関数
17.2.1. bitcast
bitcast 組み込み関数は、ある型の値のビット表現を、
別の型の値として再解釈するために使用される。
内部レイアウト規則については、§ 14.4.4 値の内部 レイアウトで説明する。
| オーバーロード |
|
| パラメーター化 | T は具象な数値スカラー または具象な数値ベクトル
|
| 説明 | 恒等変換。 成分ごとに処理される( T がベクトルの場合)。結果は e である。
|
| オーバーロード |
|
| パラメーター化 | S はi32、u32、または f32T は S ではなく、i32、u32、または f32 である
|
| 説明 | ビットを T として再解釈する。結果は、 e のビットを T 値として再解釈したものである。
|
| オーバーロード |
|
| パラメーター化 | S はi32、u32、または f32T は 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 は実行時サイズ配列の要素型である。AS はstorage、uniform、
またはworkgroupのいずれかである。アクセスモード AM はread
またはread_writeであり、
必ず AS に対して有効でなければならない。
注: |
| 説明 |
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> |
| 説明 |
逆余弦(cos-1)について、
e の主値をラジアン単位で返す。すなわち、0 ≤ x ≤ π かつ
cos(x) = e となる x を近似する。
成分ごとに処理される( |
| スカラーの定義域 | 区間 [−1, 1] |
17.5.3. acosh
| オーバーロード |
|
| パラメーター化 | S は AbstractFloat、f32、または f16 T は S または vecN<S> |
| 説明 |
逆双曲余弦(cosh-1)について、x に対する値を双曲角
として返す。すなわち、0 ≤ a ≤ +∞ かつ cosh(a) = x となる a を近似する。
成分ごとに処理される( |
| スカラーの定義域 | 区間 [1, +∞] |
17.5.4. asin
| オーバーロード |
|
| パラメーター化 | S は AbstractFloat、f32、または f16 T は S または vecN<S> |
| 説明 |
逆正弦(sin-1)について、
e の主値をラジアン単位で返す。すなわち、-π/2 ≤ x ≤ π/2 かつ
sin(x) = e となる x を近似する。
成分ごとに処理される( |
| スカラーの定義域 | 区間 [−1, 1] |
17.5.5. asinh
| オーバーロード |
|
| パラメーター化 | S は AbstractFloat、f32、または f16 T は S または vecN<S> |
| 説明 |
逆双曲正弦(sinh-1)について、y に対する値を双曲角
として返す。すなわち、 sinh(y) =
a となる a を近似する。
成分ごとに処理される( |
17.5.6. atan
| オーバーロード |
|
| パラメーター化 | S は AbstractFloat、f32、または f16 T は S または vecN<S> |
| 説明 |
逆正接(tan-1)について、
e の主値をラジアン単位で返す。すなわち、− π/2 ≤ x ≤ π/2 かつ
tan(x) = e となる x を近似する。
成分ごとに処理される( |
17.5.7. atanh
| オーバーロード |
|
| パラメーター化 | S は AbstractFloat、f32、または f16 T は S または vecN<S> |
| 説明 |
逆双曲正接(tanh-1)について、t に対する値を双曲角
として返す。すなわち、 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> |
| 説明 | 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 の余弦を返す。e の単位はラジアンである。
成分ごとに処理される(T がベクトルの場合)。
|
| スカラーの定義域 | 区間 (−∞, +∞) |
17.5.12. cosh
| オーバーロード |
|
| パラメーター化 | S は AbstractFloat、f32、または f16 T は S または vecN<S> |
| 説明 |
a の双曲余弦を返す。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> |
| 説明 | 2 の e 乗(例えば 2e)を返す。
成分ごとに処理される(T がベクトルの場合)。
|
17.5.25.
extractBits(符号付き)
| オーバーロード |
|
| パラメーター化 | T は i32 または vecN<i32>
|
| 説明 |
整数からビットを符号拡張付きで読み取る。
T がベクトルの場合)。
|
17.5.26.
extractBits(符号なし)
| オーバーロード |
|
| パラメーター化 | 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(符号付き)
| オーバーロード |
|
| パラメーター化 | T は i32 または vecN<i32>
|
| 説明 |
スカラー T の場合、結果は次のとおり:
成分ごとに処理される( |
|
注: 符号付き整数は 2 の補数表現を使用するため、 符号ビットは最上位ビット位置に現れる。 |
17.5.29. firstLeadingBit(符号なし)
| オーバーロード |
|
| パラメーター化 | 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 の床関数値を返す。
成分ごとに処理される(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 を小数部と指数部に分割する。
注: 無限大または NaN となる AbstractFloat 式は、シェーダー作成エラーを発生させる。
注: |
|
注: 値を型
|
| オーバーロード |
|
| パラメーター化 | T は vecN<f32>
|
| 説明 |
e の各成分 ei を小数部と指数部に分割する。
注: |
|
注: 値を型
|
| オーバーロード |
|
| パラメーター化 | T は vecN<f16>
|
| 説明 |
e の各成分 ei を小数部と指数部に分割する。
注: |
|
注: 値を型
|
| オーバーロード |
|
| パラメーター化 | T は vecN<AbstractFloat>
|
| 説明 |
e の各成分 ei を小数部と指数部に分割する。
注: 無限大または NaN となる AbstractFloat 式は、シェーダー作成エラーを発生させる。
注: |
|
注: 値を型
|
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>I がベクトルであるのは、T がベクトルである場合に限る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 がスカラーの場合、e の絶対値として評価される。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 を、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 が奇数なら
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 の双曲線正弦を返す。ここで 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 の双曲線正接を返す。ここで 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> |
| 説明 | 切り捨て(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 成分ベクトルを計算する。
-
ミップレベル 0 から、 線形フィルタリングによるサンプリング操作で使用される 4 つのテクセルを特定する。
-
指定された座標、配列インデックス(存在する場合)、およびオフセット(存在する場合)を使用する。
-
テクスチャ空間座標 (u,v) で考えると、テクセルは隣接して正方形を形成する。
-
テクスチャの端、キューブ面の端、またはキューブの角で選択されたテクセルは、 通常のテクスチャサンプリングと同様に処理される。
-
-
各テクセルについて、1 つのチャンネルを読み取り、スカラー値へ変換する。
-
非深度テクスチャでは、0 基点の
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 式は定数式
(例: 1)でなければならない。値は 0 以上 3 以下でなければならない。この範囲外の値は シェーダー作成エラーとなる。 |
t
| 読み取り元のサンプル対象または 深度テクスチャ。 |
s
| サンプラー型。 |
coords
| テクスチャ座標。 |
array_index
| 0 基点のテクスチャ配列インデックス。 この値は範囲 [0, textureNumLayers(t) - 1] に
クランプされる。
|
offset
|
テクスチャをサンプリングする前に、正規化されていないテクスチャ座標へ適用される
任意指定のテクセルオフセット。このオフセットは、テクスチャのラップモードを適用する前に適用される。offset 式は定数式(例:
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 つのベクトルへ収集する。
-
ミップレベル 0 から、 線形フィルタリングによる深度サンプリング操作で使用される 4 つのテクセルを特定する。
-
指定された座標、配列インデックス(存在する場合)、およびオフセット(存在する場合)を使用する。
-
テクスチャ空間座標 (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
| 深度テクスチャ。 |
s
| 比較サンプラー。 |
coords
| テクスチャ座標。 |
array_index
| 0 基点のテクスチャ配列インデックス。 この値は範囲 [0, textureNumLayers(t) - 1] に
クランプされる。
|
depth_ref
| サンプリングされた深度値との比較に使用する参照値。 |
offset
|
テクスチャをサンプリングする前に、正規化されていないテクスチャ座標へ適用される
任意指定のテクセルオフセット。このオフセットは、テクスチャのラップモードを適用する前に適用される。offset 式は定数式(例:
vec2<i32>(1, 2))でなければならない。各 offset 成分は -8 以上 7 以下で
なければならない。
この範囲外の値はシェーダー作成エラーとなる。
|
戻り値:
前述のとおり、選択されたテクセルの比較結果を持つ 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 はストレージテクセル形式 F に依存する。 テクセル形式からチャンネル形式への対応については、 テクセル形式表を参照。 |
|
| C は i32、または
u32 AM は read または read_write CF はストレージテクセル形式 F に依存する。 テクセル形式からチャンネル形式への対応については、 テクセル形式表を参照。 |
|
| C は i32、または
u32 AM は read または read_write A は i32 または u32 CF はストレージテクセル形式 F に依存する。 テクセル形式からチャンネル形式への対応については、 テクセル形式表を参照。 |
|
| C は i32、または
u32 AM は read または read_write CF はストレージテクセル形式 F に依存する。 テクセル形式からチャンネル形式への対応については、 テクセル形式表を参照。 |
|
パラメーター:
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) に、 テクスチャビューのスウィズルを 適用したもの、または
-
適切な型のベクトル (0,0,0,0) または (0,0,0,1) に、 テクスチャビューのスウィズルを 適用していないもの。
-
-
深度テクスチャでは 0.0。
17.7.5. textureNumLayers
配列化テクスチャのレイヤー(要素)数を返す。
| パラメーター化 | オーバーロード |
|---|---|
| F はテクセル形式 A はアクセスモード 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
マルチサンプルテクスチャ内の 1 テクセル当たりのサンプル数を返す。
| パラメーター化 | オーバーロード |
|---|---|
| ST は i32、
u32、または
f32 T は texture_multisampled_2d<ST>
または texture_depth_multisampled_2d
|
|
パラメーター:
t
| マルチサンプルテクスチャ。 |
戻り値:
17.7.8. textureSample
テクスチャをサンプリングする。
フラグメント シェーダーステージでのみ使用しなければならない。
一様性解析によって、この関数の呼び出しが 一様制御フロー内にあると証明できない場合、 derivative_uniformity 診断が 発生する。
| パラメーター化 | オーバーロード |
|---|---|
| |
| |
| |
| 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
| サンプリングするサンプル対象または 深度テクスチャ。 |
s
| サンプラー型。 |
coords
| サンプリングに使用するテクスチャ座標。 |
array_index
| サンプリングする 0 基点のテクスチャ配列インデックス。 この値は範囲 [0, textureNumLayers(t) - 1] に
クランプされる。
|
offset
|
テクスチャをサンプリングする前に、正規化されていないテクスチャ座標へ適用される
任意指定のテクセルオフセット。このオフセットは、テクスチャのラップモードを適用する前に適用される。offset 式は定数式(例:
vec2<i32>(1, 2))でなければならない。各 offset 成分は -8 以上 7 以下で
なければならない。
この範囲外の値はシェーダー作成エラーとなる。
|
戻り値:
サンプリングされた値。
17.7.9. textureSampleBias
ミップレベルにバイアスを適用してテクスチャをサンプリングする。
必ずフラグメントシェーダーステージでのみ 使用しなければならない。
一様性解析によって、 この関数の呼び出しが一様制御フロー内にあることを証明できない場合、 derivative_uniformity 診断が発生する。
| パラメーター化 | オーバーロード |
|---|---|
| |
| |
| A は i32 または u32 |
|
| A は i32 または u32 |
|
T は texture_3d<f32> または texture_cube<f32>
|
|
| |
| A は i32 または u32 |
|
パラメーター:
t
| サンプリングするサンプルドテクスチャ。 |
s
| sampler 型。 |
coords
| サンプリングに使用するテクスチャ座標。 |
array_index
|
サンプリングする 0 を基準としたテクスチャ配列インデックス。 この値は [0, textureNumLayers(t) - 1] の範囲にクランプされる。
|
bias
|
サンプリング前にミップレベルへ適用するバイアス。 この値は [-16.0, 15.99] の範囲にクランプされる。
|
offset
|
テクスチャのサンプリング前に、正規化されていないテクスチャ座標へ適用する省略可能な
テクセルオフセット。このオフセットは、テクスチャのラッピングモードを適用する前に
適用される。offset 式は、const-expression(例:
vec2<i32>(1, 2))でなければならない。各 offset 成分は -8 以上 7 以下でなければならない。この範囲外の値は
シェーダー作成エラーとなる。
|
戻り値:
サンプリングされた値。
17.7.10.
textureSampleCompare
深度テクスチャを サンプリングし、サンプリングされた深度値を参照値と比較する。
必ずフラグメントシェーダーステージでのみ 使用しなければならない。
一様性解析によって、 この関数の呼び出しが一様制御フロー内にあることを証明できない場合、 derivative_uniformity 診断が発生する。
| パラメーター化 | オーバーロード |
|---|---|
| |
| |
| A は i32 または u32 |
|
| A は i32 または u32 |
|
| |
| A は i32 または u32 |
|
パラメーター:
t
| サンプリングする深度テクスチャ。 |
s
| sampler_comparison 型。 |
coords
| サンプリングに使用するテクスチャ座標。 |
array_index
|
サンプリングする 0 を基準としたテクスチャ配列インデックス。 この値は [0, textureNumLayers(t) - 1] の範囲にクランプされる。
|
depth_ref
| サンプリングされた深度値と比較する参照値。 |
offset
|
テクスチャのサンプリング前に、正規化されていないテクスチャ座標へ適用する省略可能な
テクセルオフセット。このオフセットは、テクスチャのラッピングモードを適用する前に
適用される。offset 式は、const-expression(例:
vec2<i32>(1, 2))でなければならない。各 offset 成分は -8 以上 7 以下でなければならない。この範囲外の値は
シェーダー作成エラーとなる。
|
戻り値:
[0.0..1.0] の範囲内の値。
サンプリングされた各テクセルは、sampler_comparison によって定義された比較演算子を使用して
参照値と比較され、各テクセルについて 0 または 1 の値が得られる。
サンプラーがバイリニアフィルタリングを使用する場合、戻り値はこれらの値をフィルタリングした平均となる。 それ以外の場合は、単一テクセルの比較結果が返される。
17.7.11.
textureSampleCompareLevel
深度テクスチャを サンプリングし、サンプリングされた深度値を参照値と比較する。
| パラメーター化 | オーバーロード |
|---|---|
| |
| |
| A は i32 または u32 |
|
| A は i32 または u32 |
|
| |
| A は i32 または u32 |
|
パラメーター:
t
| サンプリングする深度テクスチャ。 |
s
| sampler_comparison 型。 |
coords
| サンプリングに使用するテクスチャ座標。 |
array_index
|
サンプリングする 0 を基準としたテクスチャ配列インデックス。 この値は [0, textureNumLayers(t) - 1] の範囲にクランプされる。
|
depth_ref
| サンプリングされた深度値と比較する参照値。 |
offset
|
テクスチャのサンプリング前に、正規化されていないテクスチャ座標へ適用する省略可能な
テクセルオフセット。このオフセットは、テクスチャのラッピングモードを適用する前に
適用される。offset 式は、const-expression(例:
vec2<i32>(1, 2))でなければならない。各 offset 成分は -8 以上 7 以下でなければならない。この範囲外の値は
シェーダー作成エラーとなる。
|
戻り値:
[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
| sampler。 |
coords
| サンプリングに使用するテクスチャ座標。 |
array_index
|
サンプリングする 0 を基準としたテクスチャ配列インデックス。 この値は [0, textureNumLayers(t) - 1] の範囲にクランプされる。
|
ddx
| サンプリング位置の計算に使用する x 方向の導関数ベクトル。 |
ddy
| サンプリング位置の計算に使用する y 方向の導関数ベクトル。 |
offset
|
テクスチャのサンプリング前に、正規化されていないテクスチャ座標へ適用する省略可能な
テクセルオフセット。このオフセットは、テクスチャのラッピングモードを適用する前に
適用される。offset 式は、const-expression(例:
vec2<i32>(1, 2))でなければならない。各 offset 成分は -8 以上 7 以下でなければならない。この範囲外の値は
シェーダー作成エラーとなる。
|
戻り値:
サンプリングされた値。
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
| sampler 型。 |
coords
| サンプリングに使用するテクスチャ座標。 |
array_index
|
サンプリングする 0 を基準としたテクスチャ配列インデックス。 この値は [0, textureNumLayers(t) - 1] の範囲にクランプされる。
|
level
|
ミップレベル。レベル 0 にはテクスチャのフルサイズ版が含まれる。
level が f32 である関数では、
テクスチャ形式の機能に
従って形式がフィルタリング可能な場合、小数値によって 2 つのレベル間を補間できる。
|
offset
|
テクスチャのサンプリング前に、正規化されていないテクスチャ座標へ適用する省略可能な
テクセルオフセット。このオフセットは、テクスチャのラッピングモードを適用する前に
適用される。offset 式は、const-expression(例:
vec2<i32>(1, 2))でなければならない。各 offset 成分は -8 以上 7 以下でなければならない。この範囲外の値は
シェーダー作成エラーとなる。
|
戻り値:
サンプリングされた値。
17.7.14.
textureSampleBaseClampToEdge
以下で説明するようにテクスチャ座標を端にクランプし、テクスチャビューをそのベースレベルで サンプリングする。
| パラメーター化 | オーバーロード |
|---|---|
T は texture_2d<f32> または texture_external
|
|
パラメーター:
t
| サンプリングするサンプルドテクスチャまたは外部テクスチャ。 |
s
| sampler 型。 |
coords
|
サンプリングに使用するテクスチャ座標。
サンプリング前に、指定された座標は次の矩形へクランプされる。 [ half_texel, 1 - half_texel ] ここで、 half_texel = vec2(0.5) / vec2<f32>(textureDimensions(t)) 注: 半テクセルの調整により、
サンプラーの |
戻り値:
サンプリングされた値。
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 アトミック型に対して許可される唯一の演算である。
すべてのアトミック組み込み関数は、relaxed メモリ順序付けを
使用する。これは、同期および順序付けの保証が、同じメモリ位置に作用する
アトミック操作間にのみ適用されることを意味する。アトミックメモリアクセスと非アトミックメモリアクセスの間、
または異なるメモリ位置に作用するアトミックアクセスの間には、同期や順序付けの保証は適用されない。
アトミック組み込み関数は、頂点シェーダーステージで使用してはならない。
すべてのアトミック組み込み関数における 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 )
atomic_ptr が指すアトミックオブジェクトに、値 v をアトミックに格納する。
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 を使用した
加算演算をアトミックに実行し、演算前にアトミックオブジェクトに格納されていた元の値を返す。
// All operations are performed atomically 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 を使用した
減算演算をアトミックに実行し、演算前にアトミックオブジェクトに格納されていた元の値を返す。
// All operations are performed atomically 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 を使用した
最大値演算をアトミックに実行し、演算前にアトミックオブジェクトに格納されていた元の値を返す。
// All operations are performed atomically 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 を使用した
最小値演算をアトミックに実行し、演算前にアトミックオブジェクトに格納されていた元の値を返す。
// All operations are performed atomically 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 演算をアトミックに実行し、演算前にアトミックオブジェクトに格納されていた元の値を返す。
// All operations are performed atomically 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 演算をアトミックに実行し、演算前にアトミックオブジェクトに格納されていた元の値を返す。
// All operations are performed atomically 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 演算をアトミックに実行し、演算前にアトミックオブジェクトに格納されていた元の値を返す。
// All operations are performed atomically 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 をアトミックに格納し、
演算前にアトミックオブジェクトに格納されていた元の値を返す。
// All operations are performed atomically 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 , // old value stored in the atomic exchanged : bool// true if the exchange was done }
注:
__atomic_compare_exchange_result 型の値を明示的に宣言することはできないが、
値がこの型を推論することはできる。
次の手順をアトミックに実行する。
-
atomic_ptrが指す元の値をロードする。 -
等価演算を使用して、元の値と値
cmpを比較する。 -
等価比較の結果が
trueであった場合にのみ、値vを格納する。
2 つのメンバーを持つ構造体を返す。第 1 メンバー old_value は演算前の
アトミックオブジェクトの元の値であり、第 2 メンバー exchanged は比較が成功したかどうかを示す。
// All operations are performed atomically fn atomicCompareExchangeWeak ( atomic_ptr : ptr< AS , atomic< T > , read_write> , cmp : T , v : T ) -> _atomic_compare_exchange_result < T > { let old = * atomic_ptr ; // This comparison may spuriously fail. let comparison = old == cmp ; if comparison { * atomic_ptr = v ; } return _atomic_compare_exchange_result < T > ( old , comparison ); }
注: 一部の実装では、等価比較が見かけ上失敗する
場合がある。すなわち、結果ベクトルの第 1 成分が cmp と等しい場合でも、
結果ベクトルの第 2 成分が false になることがある。
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 実行スコープを持つ。
すべての同期関数は、コンピュートシェーダーステージでのみ使用しなければならない。
すべての同期関数は、一様制御フロー内でのみ呼び出さなければならない。
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 診断を発生させる。
注: コンピュートシェーダーステージでは、 一様制御フローのスコープはワークグループである。 フラグメントシェーダーステージでは、 一様制御フローのスコープは描画コマンドである。 これらのスコープはいずれもサブグループより大きい。
17.12.1.
subgroupAdd
| オーバーロード |
|
| 前提条件 | T は具象数値スカラーまたは具象数値ベクトル
|
| 説明 |
リダクション演算。 |
17.12.1.1. subgroupExclusiveAdd
| オーバーロード |
|
| 前提条件 | T は具象数値スカラーまたは具象数値ベクトル
|
| 説明 |
排他的プレフィックススキャン演算。 サブグループ内で、
サブグループ呼び出し IDが現在の呼び出しの
ID より小さい、すべてのアクティブな呼び出しにおける
アクティブな呼び出しのうち ID が最も小さい呼び出しに対して返される値は
|
17.12.1.2. subgroupInclusiveAdd
| オーバーロード |
|
| 前提条件 | T は具象数値スカラーまたは具象数値ベクトル
|
| 説明 |
包含的プレフィックススキャン演算。 サブグループ内で、
サブグループ呼び出し IDが現在の呼び出しの
ID 以下である、すべてのアクティブな呼び出しにおける
注:
|
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 成分には呼び出し 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 は具象数値スカラーまたは具象数値ベクトル
|
| 説明 |
現在の呼び出しについて、サブグループ呼び出し IDが
subgroup_invocation_id + delta と一致する呼び出しの
e を返す。
|
17.12.12.2. subgroupShuffleUp
| オーバーロード |
|
| 前提条件 | T は具象数値スカラーまたは具象数値ベクトル
|
| 説明 |
現在の呼び出しについて、サブグループ呼び出し IDが
subgroup_invocation_id - delta と一致する呼び出しの
e を返す。
|
17.12.12.3. subgroupShuffleXor
| オーバーロード |
|
| 前提条件 | T は具象数値スカラーまたは具象数値ベクトル
|
| 説明 |
現在の呼び出しについて、サブグループ呼び出し IDが
subgroup_invocation_id ^ mask と一致する呼び出しの
e を返す。
|
17.12.13.
subgroupXor
| オーバーロード |
|
| 前提条件 | T は i32、u32、vecN<i32>、または vecN<u32>
|
| 説明 |
リダクション演算。 |
17.13. クアッド操作
§ 15.6.4 クアッド操作を参照。
これらの関数の呼び出しは、次の条件を満たす:
-
一様性解析によって、呼び出しが一様制御フロー内にあることを証明できない場合、 subgroup_uniformity 診断を トリガーする。
注: コンピュートシェーダーステージでは、 一様制御フローのスコープは ワークグループである。 フラグメント シェーダーステージでは、一様制御フローのスコープは 描画コマンドである。 これらのスコープはいずれもクアッドより大きい。
17.13.1.
quadBroadcast
| オーバーロード |
|
| 前提条件 | T は具象数値スカラーまたは具象数値ベクトルI はu32またはi32
|
| 説明 |
クアッド内でクアッド呼び出し IDが
id と一致する呼び出しの e の値を、クアッド内のすべてのアクティブな呼び出しへ返す。
注: subgroupBroadcast とは異なり、現時点では 非定数の代替手段は存在しない。 |
17.13.2.
quadSwapDiagonal
| オーバーロード |
|
| 前提条件 | T は具象数値スカラーまたは具象数値ベクトル
|
| 説明 |
クアッド内で反対側の座標にある呼び出しの
e の値を返す。
すなわち:
|
17.13.3.
quadSwapX
| オーバーロード |
|
| 前提条件 | T は具象数値スカラーまたは具象数値ベクトル
|
| 説明 |
クアッド内で同じ X 次元を共有する呼び出しの
e の値を返す。
すなわち:
|
17.13.4.
quadSwapY
| オーバーロード |
|
| 前提条件 | T は具象数値スカラーまたは具象数値ベクトル
|
| 説明 |
クアッド内で同じ Y 次元を共有する呼び出しの
e の値を返す。
すなわち:
|
17.14. バッファービュー組み込み関数
これらの関数はすべて、buffer_view 言語機能を必要とする。
これらの関数は、バッファーへのポインターを操作する。 bufferView および bufferArrayView は、バッファー内の不透明なデータを別の ホスト共有可能なデータ型として再解釈する。 結果のポインターは、ほかのポインターと同様に使用できる。
ArrayOffset(T) を次のように定義する:
-
T が、最後のメンバーとして実行時サイズ配列(array<E>)を持つ 構造体である場合、 OffsetOfMember(T, lastMemberIndex)
-
それ以外の場合は 0
MinTypeSize(T) を次のように定義する:
-
T が、最後のメンバーとして実行時サイズ配列を持つ 構造体である場合、 ArrayOffset(T) + StrideOf(array<E>)
関数呼び出しへのバッファーポインター引数は、 パラメーターの型への自動変換を 受けることができるため、実装は手続き間解析を使用して、 無効なメモリ参照の有無を検査するとともに、 正しい結果を保証する。 任意のバッファービュー組み込み関数に使用されるバッファーサイズは、その呼び出しで使用される特定の 起点変数について検出された最小バッファーサイズである。 これは動的な概念であるため、実装は、組み込み関数の特定のインスタンスについてこの値が正しく決定されることを 保証する。 サイズは次の値の最小値となる:
-
起点変数のサイズ、または
-
呼び出しスタック内で仮パラメーターとして検出された、 最小の固定サイズバッファー。
注: 実装が unrestricted_pointer_parameters 言語機能をサポートしない場合、組み込み関数への引数の ルート識別子は、 起点変数で なければならない。
注: バッファーを関数へ渡す際に、 そのサイズを大きくすることはできない。
17.14.1.
bufferView
| オーバーロード |
|
| 前提条件 |
AS はstorage、uniform、または
workgroupのいずれかである。AM は AS に対して有効なアクセスモードである。
|
| 説明 |
p の先頭から offset バイト離れた
メモリビューを
型 T として再解釈する。
すなわち、p に関連付けられたメモリ位置が範囲
[0, bufferLength(p)) 内にある場合、結果に関連付けられた
メモリ位置は、格納型
T を持つ範囲
[offset, bufferLength(p)) 内となる。
MinTypeSize(
注: これは uniform_buffer_standard_layout 言語機能と相互作用する。 |
| オーバーロード |
|
| 前提条件 |
AS はstorage、uniform、または
workgroupのいずれかである。AM は AS に対して有効なアクセスモードである。
|
| 説明 |
p の先頭から offset バイト離れた
メモリビューを
型 T として再解釈する。
すなわち、p に関連付けられたメモリ位置が範囲
[0, bufferLength(p)) 内にある場合、結果に関連付けられた
メモリ位置は、格納型
T を持つ範囲
[offset, bufferLength(p)) 内となる。
MinTypeSize(
注: これは uniform_buffer_standard_layout 言語機能と相互作用する。 |
requires buffer_view ; @group ( 0 ) @binding ( 0 ) var < storage> in : buffer ; @group ( 0 ) @binding ( 1 ) var < storage, read_write> out : buffer ; struct S { a : mat3x3f, b : vec2f, } fn foo ( offsets : array< u32, 4 > ) { // Read and write some of the data as vec4u. let p1 = bufferView < vec4u> ( & in , offsets [ 0 ]); * bufferView < vec4u> ( & out , offsets [ 1 ]) = * p1 ; // Read and write some of the other data via a structure. let p2 = bufferView < array< S , 2 >> ( & in , offsets [ 2 ]); let v = ( * p2 )[ 1 ]. a ; * bufferView < mat3x3f> ( & out , offsets [ 3 ]) = v ; }
17.14.2.
bufferArrayView
| オーバーロード |
|
| 前提条件 |
AS はstorage、uniform、または
workgroupのいずれかである。AM は AS に対して有効なアクセスモードである。
|
| 説明 |
p の先頭から offset バイト離れた位置から
size バイト分のメモリビューを、型
T として再解釈する。
すなわち、p に関連付けられたメモリ位置が範囲
[0, bufferLength(p)) 内にある場合、結果に関連付けられた
メモリ位置は、格納型
T を持つ範囲
[offset, offset + size) 内となる。
MinTypeSize(
注: これは uniform_buffer_standard_layout 言語機能と相互作用する。 (
|
| オーバーロード |
|
| 前提条件 |
AS はstorage、uniform、または
workgroupのいずれかである。AM は AS に対して有効なアクセスモードである。
|
| 説明 |
p の先頭から offset バイト離れた位置から
size バイト分のメモリビューを、型
T として再解釈する。
すなわち、p に関連付けられたメモリ位置が範囲
[0, bufferLength(p)) 内にある場合、結果に関連付けられた
メモリ位置は、格納型
T を持つ範囲
[offset, offset + size) 内となる。
MinTypeSize(
MinTypeSize(
注: これは uniform_buffer_standard_layout 言語機能と相互作用する。 (
|
requires buffer_view ; const stride = 32 ; const N = 4 ; const size = 2048 ; const_assert stride * N < size ; struct strided_u32 { @size ( stride ) a : u32, } @group ( 0 ) @binding ( 0 ) var < uniform> in : buffer < size > ; @group ( 0 ) @binding ( 1 ) var < storage, read_write> out : array< u32, N > ; fn foo ( offsets : u32) { // Read a strided array from in and copy it unstrided to out. var tmp : array< u32, N > ; let view = bufferArrayView < array< strided_u32 >> ( & in , offset , stride * N ); for ( var i = 0 ; i < N ; i ++ ) { tmp [ i ] = ( * view )[ i ]; } out = tmp ; }
17.14.3.
bufferLength
| オーバーロード |
|
| 前提条件 |
AS はstorage、uniform、または
workgroupのいずれかである。AM は AS に対して有効なアクセスモードである。
|
| 説明 |
手続き間解析中に検出された、p が指すバッファーの最小サイズを返す。
実行時サイズバッファーのみが検出された場合は、
WebGPU の GPUBuffer のサイズを返す。
|
requires buffer_view ; requires unrestricted_pointer_parameters ; @group ( 0 ) @binding ( 0 ) var < storage> b1 : buffer < 2048 > ; @group ( 0 ) @binding ( 0 ) var < storage> b2 : buffer < 4096 > ; fn foobar ( p : ptr< storage, buffer > ) -> u32{ return bufferLength ( p ); } fn bar ( p : ptr< storage, buffer < 1024 >> ) -> u32{ return foobar ( p ); } fn foo ( p : ptr< storage, buffer < 256 >> ) -> u32{ return bufferLength ( p ); } @compute @workgroup_size ( 1 ) fn main () { let len1 = bufferLength ( & b1 ); // 2048 let len2 = bufferLength ( & b2 ); // 4096 let len3 = foo ( & b1 ); // 256 let len4 = foo ( & b2 ); // 256 let len5 = bar ( & b1 ); // 1024 let len6 = bar ( & b2 ); // 1024 let len7 = foobar ( & b1 ); // 2048 let len8 = foobar ( & b2 ); // 4096 }
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
- 必須パラメーター
-
該当なし
- 任意パラメーター
-
なし
- エンコーディングに関する考慮事項
-
binary
WGSL は、バイトオーダーマーク(BOM)を付けずに UTF-8 エンコーディングを使用する Unicode テキストである。 § 3 テキスト構造を参照。
- セキュリティに関する考慮事項:
-
WebGPU Shading Language(WGSL)は、WebGPU API のコンテキストで実行される GPU コード用の プログラミング言語である。セキュリティに関する考慮事項については、 [WebGPU] の 2.1 節「セキュリティに関する考慮事項」を参照。 プライバシーに関する考慮事項については、[WebGPU] の 2.2 節「プライバシーに関する考慮事項」を参照。
- 相互運用性に関する考慮事項:
-
WebGPU の実装は異なる能力を持つ場合があり、その相違は WGSL プログラムが利用できる機能に影響する可能性がある。 [WebGPU] の 3.6 節「任意の能力」、および§ 4.1.2 言語拡張を参照。
実装は、この登録が WGSL の後続版にも適用されるものとして動作すると期待されており、 公開された仕様への参照は、それに応じて随時更新される場合がある。 この期待はメディアタイプの登録としては一般的ではないが、広く普及している業界慣行と一致する。
- 公開仕様:
-
WebGPU シェーディング言語
- このメディアタイプを使用するアプリケーション:
-
WebGPU の実装。これにはウェブブラウザーが含まれると予想される。
- フラグメント識別子に関する考慮事項
-
なし
- 追加情報:
-
マジックナンバー: なし
ファイル拡張子:
.wgslMacintosh ファイルタイプコード:
TEXT - 詳細情報の連絡先担当者およびメールアドレス:
-
David Neto(dneto@google.com)、または WGSL に記載されている編集者。
- 想定される用途
-
COMMON
- 作成者
-
W3C。WGSL に記載されている編集者を参照。
- 変更管理者
-
W3C
- 規範的な参考文献
-
[WebGPU] W3C, "WebGPU” W3C ワーキングドラフト、2023 年 1 月。https://w3.org/TR/webgpu
WebGPU Shading Language、W3C、「WebGPU Shading Language」、W3C ワーキングドラフト、2023 年 1 月。 https://w3.org/TR/WGSL