1. 序論
WebGPU Shading Language (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 つ以上の呼び出しに分割され、 それぞれがエントリーポイントを実行しますが、条件はわずかに異なります。 シェーダーステージ内の呼び出しは、特定の変数へのアクセスを共有します:
-
ステージ内のすべての呼び出しは、シェーダーインターフェイス内のリソースを共有します。
-
コンピュート シェーダーでは、同じ ワークグループ内の呼び出しが、 workgroup アドレス空間内の変数を共有します。 異なるワークグループ内の呼び出しは、それらの変数を共有しません。
ただし、呼び出しは異なるシェーダーステージ入力の集合に作用します。これには、 呼び出しを他の呼び出しと区別する識別値を提供する組み込み入力も含まれます。 各呼び出しには、private およびfunction アドレス空間内の変数という形式で、 独立した独自のメモリー空間があります。
シェーダーステージ内の呼び出しは同時に実行され、多くの場合並列に実行されることがあります。 シェーダー作者は、シェーダーステージ内の呼び出しの動的な動作が次を満たすようにする責任があります:
-
テクスチャーサンプリングや制御バリアなど、特定のプリミティブ操作の 一様性要件を満たす。
-
共有変数への競合する可能性のあるアクセスを調整し、データ競合を回避する。
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 の転置は、 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 メソッドで利用可能なその他の情報のみに依存します。 この仕様でプログラムが何かを実行しなければならない(must)と記述している文は、 一般に、それらの要件に違反した場合にシェーダー作成エラーを発生させます。 -
パイプライン作成エラーは、 パイプライン作成時に検出可能なエラーです。 検出は、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 | error | 導関数を計算する組み込み関数の 任意の呼び出し サイトの位置。 つまり、次のいずれかの呼び出しの位置: |
組み込み関数の呼び出しが導関数を計算するが、一様性解析で
その呼び出しが一様な制御フロー内で発生することを証明できない場合。
§ 15.2 一様性を参照してください。 |
| subgroup_uniformity | error | 任意のサブグループまたはクアッド 組み込み関数の呼び出し サイトの位置。 |
サブグループまたはクアッド組み込み関数の呼び出しだが、一様性解析で
その呼び出しが一様な制御フロー内で発生することを証明できない場合。
さらに、一様性解析で次のパラメーター値が一様であることを証明できない場合:
§ 15.2 一様性を参照してください。 |
単一の診断 name-tokenで構成される、 認識されないトリガールールを使用した場合、ユーザーエージェントは警告を トリガーするべきです。
実装は、ここで指定されていないトリガールールをサポートしてもかまいません。 ただし、それらはdiagnostic_rule_name の複数トークン形式を使用して記述されなければなりません。 複数トークン形式で記述された認識されないトリガールールの使用自体が、 診断をトリガーしてもかまいません。
この仕様の将来のバージョンでは、特定の規則を削除したり、その既定の重大度を弱めたり
(つまり、現在の既定値をより低い重大度の既定値に置き換えたり)しても、後方互換性を
満たしていると見なされる場合があります。
たとえば、WGSL の将来のバージョンでは、derivative_uniformity の既定の重大度を error から
warning または info に変更する可能性があります。
仕様にそのような変更が加えられた後も、それ以前に有効だったプログラムは有効なままです。
2.3.3. 診断フィルタリング
フィルター可能なトリガールールを持つ診断が トリガーされると、WGSL は 診断を破棄したり、その重大度を変更したりするための機構を提供します。
診断フィルター DF には 3 つのパラメーターがあります:
診断フィルター DF(AR,NS,TR) を診断 D に適用すると、 次の効果があります:
範囲診断
フィルターは、診断フィルターのうち、その影響範囲が指定された
ソーステキストの範囲であるものです。
範囲診断フィルターは、次の表に示すように、影響を受けるソース範囲の先頭に
@diagnostic 属性として指定します。
@diagnostic 属性は、それ以外の場所に現れてはなりません。
| 配置 | 影響範囲 |
|---|---|
| 複合文の先頭。 | 複合文。 |
| 関数宣言の先頭。 | 関数宣言。 |
| if 文の先頭。 | if 文: if_clause と、関連付けられたすべてのelse_if_clause およびelse_clause 節。 すべての制御条件式を含みます。 |
| switch 文の先頭。 | switch 文: セレクター式およびswitch_body。 |
| switch_body の先頭。 | switch_body。 |
| loop 文の先頭。 | loop 文。 |
| while 文の先頭。 | while 文: 条件式とループ本体の両方。 |
| for 文の先頭。 | for 文: for_header およびループ本体。 |
loop、while、またはfor ループのループ本体の開始波括弧('{')の直前。
| ループ本体。 |
| continuing_compound_statement の先頭。 | continuing_compound_statement。 |
注: 次のものも複合文です: 関数本体、case 節、default-alone 節、 while およびfor ループの本体、 ならびにif_clause、else_if_clause、およびelse_clause の本体。
var < private> d : f32; fn helper () -> vec4< f32> { // 「if」の本体で derivative_uniformity 診断を // 無効にする。 if ( d < 0.5 ) @diagnostic ( off , derivative_uniformity ) { return textureSample ( t , s , vec2( 0 , 0 )); } return vec4( 0.0 ); }
グローバル 診断フィルターを使用すると、WGSL モジュール全体に診断フィルターを適用できます。
diagnostic ( off , derivative_uniformity ); var < private> d : f32; fn helper () -> vec4< f32> { if ( d < 0.5 ) { // ここではグローバル診断フィルターによって // derivative_uniformity 診断が無効にされている。 return textureSample ( t , s , vec2( 0 , 0 )); } else { // derivative_uniformity 診断は 'warning' 重大度に設定される。 @diagnostic ( warning , derivative_uniformity ) { return textureSample ( t , s , vec2( 0 , 0 )); } } return vec4( 0.0 ); }
2 つの診断フィルター DF(AR1,NS1,TR1) と DF(AR2,NS2,TR2) は、 次の場合に競合します:
-
(AR1 = AR2)、かつ
-
(TR1 = TR2)、かつ
-
(NS1 ≠ NS2)。
注: 複数のグローバル診断フィルターは、 競合しない場合に許可されます。
WGSL の診断フィルターは、その影響範囲が完全に入れ子になるよう設計されています。 DF1 の影響範囲と DF2 の影響範囲が重なる場合、 DF1 の影響範囲が DF2 の影響範囲に完全に含まれるか、その逆のいずれかです。
ソース位置 L およびトリガールール TR に対する 最も近い包含診断フィルターは、存在する場合、 次を満たす診断フィルター DF(AR,NS,TR) です:
-
L が影響範囲 AR 内にあり、かつ
-
L が AR' 内にある別のフィルター DF'(AR',NS',TR) が存在する場合、 AR が AR' に含まれる。
影響範囲は入れ子になるため、最も近い包含診断フィルターは:
-
一意の範囲診断フィルターであるか、
-
そうでなければ、重複する(競合しない)グローバル診断 フィルターの集合の 1 つであるか、
-
そうでなければ存在しません。
2.4. 制限
WGSL 実装は、次の制限を満たすシェーダーをサポートします。 WGSL 実装は、指定された制限を超えるシェーダーをサポートしてもかまいません。
注: WGSL 実装は、 指定された制限を超えるシェーダーをサポートしない場合、エラーを発行するべきです。
| 制限 | サポートされる最小値 |
|---|---|
| 構造体型のメンバーの最大数 | 1023 |
| 複合型の最大ネスト 深度 | 15 |
| 関数内で波括弧によって囲まれた文の最大ネスト深度 | 127 |
| 関数のパラメーターの最大数 | 255 |
| switch 文における case セレクター値の最大数。 各 case 文について、default 節を含む case 値の数を合計したもの。 | 1023 |
| 単一のシェーダーによって 静的にアクセスされる 、 private アドレス空間にインスタンス化された すべての変数の 合計バイトサイズの最大値 | 8192 |
| 単一の関数で 宣言され、 function アドレス空間にインスタンス化された すべての変数の 合計バイトサイズの最大値 | 8192 |
|
単一のシェーダーによって
静的にアクセスされる
、 workgroup アドレス空間にインスタンス化された
すべての変数の
合計バイトサイズの最大値
この制限の目的では、 override 値を代入するとき、固定フットプリント配列は作成時固定フットプリント配列として扱われます。 これは WebGPU のmaxComputeWorkgroupStorageSize 制限を 独立した WGSL 制限に対応付けます。 | 16384 |
|
即時データ
変数の
最大バイトサイズ。
これは WebGPU のmaxImmediateSize 制限を 独立した WGSL 制限に対応付けます。 | 64 |
| 配列型の値 コンストラクター式における要素の最大数 | 2047 |
3. テキスト構造
text/wgsl メディアタイプは、コンテンツを WGSL モジュールとして識別するために使用されます。
付録 A: text/wgsl メディアタイプを参照してください。
WGSL モジュールは、バイトオーダーマーク (BOM) を持たない UTF-8 エンコーディングの Unicode テキストです。
WGSL モジュールのテキストは、Unicode コードポイントのシーケンスからなり、連続した空でない集合として次のものにグループ化されます:
プログラムテキストには null コードポイント (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 を significand と同じものとしますが、 20 番目の有効桁より 右にある各桁を 0 に置き換えます。
-
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 を significand と同じものとしますが、 16 番目の有効桁より 右にある各桁を 0 に置き換えます。
-
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 モジュールの意味が変わるなら、 ユーザーエージェントは開発者から見える警告を発行するべきです。 (同形異義文字とは、別のコードポイントシーケンスと読者には同じように見える可能性があるコードポイントのシーケンスです。 同形異義文字を検出するための対応付けの例としては、前段落で述べた 変換、対応付け、およびマッチングアルゴリズムがあります。 識別子が部分シーケンスをその同形異義文字で繰り返し置き換えることで一方を他方に 変換できる場合、2 つのコードポイントシーケンスは同形異義です。)
3.8. コンテキスト依存名
コンテキスト依存 名は、概念に名前を付けるために使用されるトークンですが、 特定の文法的コンテキストでのみ使用されます。 トークンの綴りは識別子と同じ場合がありますが、そのトークンは宣言されたオブジェクトに解決されません。 この節では、コンテキスト依存名として使用されるトークンを列挙します。 トークンはキーワードまたは予約語であってはなりません。
3.8.1. 属性名
§ 12 属性を参照してください。
属性名は次のとおりです:
3.8.2. 組み込み値名
組み込み値 name-tokenは、組み込み値の 名前で使用されるトークンです。
§ 13.3.1.1 組み込み入力と出力を参照してください。
組み込み値名は 次のとおりです:
3.8.3. 診断ルール名
診断 name-tokenは、診断のトリガールールの名前で使用されるトークンです。
§ 2.3 診断を参照してください。
事前定義された診断ルール名は次のとおりです:
3.8.4. 診断重大度制御名
有効な診断 フィルターの重大度制御名は§ 2.3 診断に列挙されていますが、 識別子と同じ形式を持ちます:
診断フィルターの 重大度制御名は次のとおりです:
3.8.5. 拡張名
有効なenable-extension 名は§ 4.1.1 Enable 拡張に列挙されていますが、一般には 識別子と同じ形式を持ちます:
enable-extension 名は次のとおりです:
有効な言語 拡張名は§ 4.1.2 言語拡張に列挙されていますが、 一般には識別子と同じ形式を持ちます:
言語 拡張名は次のとおりです:
3.8.6. 補間型名
補間型 name-tokenは、interpolate_type_name の補間型の名前で使用されるトークンです。
§ 13.3.1.4 補間を参照してください。
補間 型名は次のとおりです:
3.8.7. 補間サンプリング名
補間サンプリング name-tokenは、補間 サンプリングの名前で使用されるトークンです。
§ 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. 深度モード名
深度モード name-tokenは、fragment_depth 機能がサポートされている場合に、 frag_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 に追加します。
T を Pending スタックからポップします。
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 仕様に対する一貫した変更の集合に名前を付けてグループ化したものであり、 次の任意の組み合わせからなります:
-
新しい構文による新しい概念および動作の追加。これには次が含まれます:
-
宣言、文、属性、および組み込み関数。
-
-
現在の仕様または以前に公開された拡張における制限の削除。
-
許容される動作の集合を減らすための構文。
-
プログラムの一部で利用可能な機能を制限するための構文。
-
拡張が既存の仕様、および任意で他の拡張とどのように相互作用するかの説明。
仮に、拡張では次のことが可能です:
-
異なるビット幅の整数など、新しい数値スカラー型を追加する。
-
浮動小数点の丸めモードを制約する構文を追加する。
-
シェーダーがアトミック型を使用しないことを示す構文を追加する。
-
新しい種類の文を追加する。
-
新しい組み込み関数を追加する。
-
シェーダー呼び出しの実行方法を制約する構文を追加する。
-
新しいシェーダーステージを追加する。
拡張には 2 種類あります: enable-extension と言語拡張です。
4.1.1. 拡張の有効化
enable-extensionは、 次のすべてを満たす場合にのみ機能を利用できる拡張です:
-
実装がそれをサポートし、かつ
-
シェーダーがenable ディレクティブによって明示的に要求し、かつ
-
対応する WebGPU
GPUFeatureNameが、GPUDeviceの作成時に要求された必須機能の 1 つであった場合。
Enable-extensionは、 普遍的にはサポートされていないハードウェア機能を公開することを目的としています。
enable ディレクティブは、 1 つ以上の enable-extension のサポートを有効にするディレクティブです。 実装が列挙された enable-extension のすべてをサポートしていない場合、シェーダー作成 エラーになります。
'enable' enable_extension_list ';'
他のディレクティブと同様に、enable ディレクティブが存在する場合、それはすべての宣言およびconst アサーションより前に現れなければなりません。 拡張名は識別子ではありません: 宣言に解決されません。
有効なenable-extensionを次の表に示します。
| WGSL enable-extension | 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 も自動的に有効になります。
|
atomic_vec2u_min_max
| "atomic-vec2u-min-max"
| 組み込み関数 atomicStoreMin および atomicStoreMax を、storage アドレス空間内のatomic<vec2<u32>> 型に対して有効に使用できます。それ以外の場合、これらを使用すると シェーダー作成エラーになります。 |
// 任意精度浮動小数点型のための仮想的な拡張を有効にする。 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-directiveは、 プログラムによる 1 つ以上の言語拡張の使用を文書化するディレクティブです。 実装が公開する機能は変更しません。 実装が必須拡張のいずれかをサポートしていない場合、シェーダー作成 エラーになります。
WGSL モジュールは、requires-directive を使用して、移植性がない可能性を示し、 移植性に対する意図された最低条件を示すことができます。
注: WebGPU 実装の外部にあるツールは、 プログラムで使用されるすべての言語拡張が、そのプログラム内のrequires-directiveによって網羅されているかどうかを確認できます。
'requires' language_extension_list ';'
language_extension_name ( ',' language_extension_name ) * ',' ?
他のディレクティブと同様に、requires-directive が存在する場合、それはすべての宣言およびconst アサーションより前に現れなければなりません。 拡張名は識別子ではありません: 宣言に解決されません。
| WGSL 言語拡張 | 説明 |
|---|---|
| readonly_and_readwrite_storage_textures | ストレージテクスチャーで、 read およびread_write アクセスモードを使用できるようにします。 さらに、textureBarrier 組み込み関数を追加します。 |
| packed_4x8_integer_dot_product | dot4U8Packed および dot4I8Packed 組み込み関数を使用する内積命令への入力として、 4 成分の 8 ビット整数ベクトルをパックした 32 ビット整数スカラーの使用をサポートします。 さらに、pack4xI8、pack4xU8、 pack4xI8Clamp、pack4xU8Clamp、 unpack4xI8、およびunpack4xU8 組み込み関数による、4 成分の 8 ビット整数ベクトルをパックしたパッキングおよびアンパッキング命令を追加します。 |
| unrestricted_pointer_parameters | ユーザー定義関数から、次の制限を削除します: |
| pointer_composite_access |
ルート式がポインターであり、参照を生成する複合値
分解式をサポートします。
たとえば、 同様に、 |
| uniform_buffer_standard_layout | uniform アドレス空間内のバッファーが、 他のアドレス空間と同じメモリーレイアウト制約を使用できるようにします。 |
| subgroup_id | subgroups 拡張が有効な場合に、subgroup_id およびnum_subgroups 組み込み値を使用できるようにします。 |
| subgroup_uniformity |
サブグループおよび
クアッド組み込み関数の一様な制御フローに対して、
同じサブグループ内の
すべての呼び出しを対象とする追加のスコープ「subgroup」を追加します。
注: サブグループおよびクアッド 組み込み関数を使用するには、 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 組み込みに、
depth_mode という新しい組み込みパラメーターを導入します。
モードはless およびgreater で、
フラグメントシェーダーが、既存の深度より小さい(または大きい)ことが
保証された深度値のみを書き込むと宣言するときに使用されます。
|
| buffer_view |
buffer 型および
buffer_view 組み込み関数の使用を有効にします。
他のホスト共有可能型として再解釈できる不透明な格納型を持つ 変数の宣言を可能にします。 |
| swizzle_assignment |
スウィズルビュー
型をサポートします。
これによりスウィズル代入が有効になります: 単一の代入文で、ベクトル全体を更新することなく、 ベクトルの複数の成分を更新できます。 たとえば、変数 pointer_composite_access
もサポートされている場合、
これはポインターでも機能します。 |
| atomic_vec2u_min_max | atomic<vec2<u32>> オブジェクトに対する atomicStoreMin および atomicStoreMax 組み込み関数をサポートします。 |
注: 意図としては、時間の経過とともに WGSL が、 その時点で一般的にサポートされている言語拡張内のすべての機能を具体化する言語拡張を定義することです。 requires-directive では、これらは そのような一般的な機能をすべて列挙するための短縮記法として機能します。 それらは段階的に増加する機能の集合を表し、ある意味では言語バージョンと考えることができます。
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 文法規則のいずれかとして
構文解析されたソーステキストの一部分です。
式 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 は次の 4 つの型のいずれかを表すことができます:
bool、vec2<bool>、
vec3<bool>、または vec4<bool>。
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 つ目は、const 式を、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 がともにconst 式であり、Dest が Src の引数に対応する 仮引数の型である場合 | N2 < N1 の場合は 1、 それ以外は infinity | 固定サイズバッファーのポインター引数を、より小さいサイズの ポインターパラメーターへ変換します。1 |
| ptr<AS, buffer<N>, AM> Src が関数呼び出しへの引数の型である場合 | ptr<AS, buffer, AM> Dest が Src の引数に対応する仮引数の型である場合 | 1 | 固定サイズバッファーのポインター引数をランタイムサイズバッファーのポインターパラメーターへ変換します。1 |
| S | T 上記の場合が適用されない場合 | infinity | 他の型の間には自動変換はありません。 |
-
これらの変換には、unrestricted_pointer_parameters およびbuffer_view 言語機能が必要です。
型 T が型 S の具象化であるのは、次の場合です:
-
Tが具象であり、かつ -
Tが参照型ではなく、かつ -
Tがスウィズルビュー型ではなく、かつ -
ConversionRank(
S,T) が有限であり、かつ -
上記の基準を満たす他の任意の型
T2について、ConversionRank(S,T2) > ConversionRank(S,T)。
型 T の値 e の値の
具象化とは、e に対して、T を T の
具象化へ対応付ける実行可能な変換を適用して得られる値です。
注: f32 への変換は常にf16 より優先されるため、 自動変換がf16 値を生成するのは、 モジュールでf16 拡張が有効な場合だけです。
6.1.3. オーバーロード解決
複数の型規則が構文句に適用される場合、 どれを有効にするべきかを決定するために タイブレーク手順を使用します。 この手順をオーバーロード解決と呼び、 部分式の静的型を見つける型チェックが すでに成功しているものと仮定します。
構文 句 P と、P に適用されるすべての型規則を考えます。 オーバーロード解決アルゴリズムでは、これらの型規則をオーバーロード候補と呼びます。 各候補について:
P に対するオーバーロード解決は、単一の最も望ましいオーバーロード 候補を見つけることを目的として、次のように進めます:
-
各候補 C について、構文句内の部分式の変換ランクを列挙します。 候補の前提条件は満たされているため、P 内の i 番目の部分式について:
-
その静的型は計算済みです。
-
式の静的型から、前提条件内の対応する型アサーションが要求する型への 実行可能な自動変換があります。 C.R(i) を、その変換のConversionRank とします。
-
-
実行可能な自動変換後、その部分式の 1 つが抽象型に解決される一方で、 候補の別の部分式がconst 式ではない候補を除外します。
注: その結果、句内のいずれかの部分式が const 式でない場合、 句内のすべての部分式は具象型を持たなければなりません。
-
候補を順位付けします: 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)。
-
-
最初のオーバーロードが望ましい候補であり、型チェックは成功します。
-
結果の計算は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 から構築可能型への最も優先される自動変換は // AbstractInt から i32 で、変換ランクは 2。したがって '1' は i32 と推論される。 let some_i32 = 1 ; // let some_i32: i32 = 1i; と同様 // 宣言型から推論される。 var i32_from_type : i32= 1 ; // 変数は i32 を保持する。AbstractInt から i32、変換ランク 2 var u32_from_type : u32= 1 ; // 変数は u32 を保持する。AbstractInt から u32、変換ランク 3 // 接尾辞のない整数リテラルは、必要に応じて浮動小数点へ変換できる: // AbstractInt を f32 に自動変換する。変換ランクは 5。 var f32_promotion : f32= 1 ; // 変数は f32 を保持する // 無効: 浮動小数点から整数への実行可能な変換はない var i32_demotion : i32= 1.0 ; // 無効 // 式から推論される。 var u32_from_expr = 1 + u32_1 ; // 変数は u32 を保持する var i32_from_expr = 1 + i32_1 ; // 変数は i32 を保持する // 値は表現可能でなければならない。 let u32_too_large : u32= 1234567890123456890 ; // 無効、オーバーフロー let i32_too_large : i32= 1234567890123456890 ; // 無効、オーバーフロー let u32_large : u32= 2147483649 ; // 有効 let i32_large : i32= 2147483649 ; // 無効、オーバーフロー let f32_out_of_range1 = 0x1p500 ; // 無効、範囲外 let f32_hex_lost_bits = 0x1.0000000001p0 ; // 無効、f32 で正確に表現できない // 最小整数: AbstractInt に単項否定を適用し、その後 i32 を推論する。 // AbstractInt から構築可能型への最も優先される変換(最小の // 変換ランク)は AbstractInt から i32。 let i32_min = - 2147483648 ; // 型は i32 // 無効。上記と同様に AbstractInt から i32 を選択するが、値が // 範囲外であり、シェーダー作成エラーになる。 let i32_too_large_2 = 2147483648 ; // 無効。 // 部分式は AbstractInt および AbstractFloat に解決できる。 // 次の例はすべて有効で、変数の値は 6u。 var u32_expr1 = ( 1 + ( 1 + ( 1 + ( 1 + 1 )))) + 1u ; var u32_expr2 = 1u + ( 1 + ( 1 + ( 1 + ( 1 + 1 )))); var u32_expr3 = ( 1 + ( 1 + ( 1 + ( 1u + 1 )))) + 1 ; var u32_expr4 = 1 + ( 1 + ( 1 + ( 1 + ( 1u + 1 )))); // 組み込み関数のパラメーターに基づく推論。 // 最優先候補は clamp(i32,i32,i32)->i32 let i32_clamp = clamp ( 1 , - 5 , 5 ); // 最優先候補は clamp(u32,u32,u32)。 // リテラルは AbstractInt から u32 への自動変換を使用する。 let u32_clamp = clamp ( 5 , 0 , u32_from_expr ); // 最優先候補は clamp(f32,f32,f32)->f32 // リテラルは AbstractInt から f32 への自動変換を使用する。 let f32_clamp = clamp ( 0 , f32_1 , 1 ); // 次の例はすべて、初期値 10f を持つ f32 に昇格する。 let f32_promotion1 = 1.0 + 2 + 3 + 4 ; let f32_promotion2 = 2 + 1.0 + 3 + 4 ; let f32_promotion3 = 1f + (( 2 + 3 ) + 4 ); let f32_promotion4 = (( 2 + ( 3 + 1f )) + 4 ); // 型規則違反。 // 無効。初期化子は f32 にしか解決できない: // AbstractFloat から u32 への実行可能な自動変換はない。 let mismatch : u32= 1.0 ; // 無効。符号の異なるパラメーターを許可する clamp のオーバーロードはない。 let ambiguous_clamp = clamp ( 1u , 0 , 1i ); // 推論は文レベルで完了する。 // let 宣言の初期化子は構築可能(またはポインター)でなければならない。 // AbstractInt から構築可能型への最も優先される自動変換は // AbstractInt から i32 で、変換ランクは 2。したがって '1' は i32 と推論される。 let some_i32 = 1 ; // let some_i32: i32 = 1i; と同様 let some_f32 : f32= some_i32 ; // 型エラー: i32 は f32 に代入できない // 別のオーバーフローの例 let overflow_u32 = ( 1 - 2 ) + 1u ; // 無効、-1 は u32 の範囲外 // 理想値は 32 ビットの範囲外だが、その後範囲内に戻される let out_and_in_again = ( 0x1ffffffff / 8 ); // 同様だが無効 let out_of_range = ( 0x1ffffffff / 8u ); // 計算を 32 ビットで行う必要があり、 // 0x1ffffffff が範囲外になる。
6.2.2. ブール型
bool 型は、
true および false の値を含みます。
| 前提条件 | 結論 | 説明 |
|---|---|---|
true: bool
| true 値。 | |
false: bool
| false 値。 |
6.2.3. 整数型
u32 型は、32 ビット 符号なし整数の集合です。
i32 型は、32 ビット 符号付き整数の集合です。 符号ビットを最上位ビット位置に持つ 2 の補数表現を使用します。
オーバーフローする具象整数型に対する式は、 2bitwidth を法とする結果を生成します
| 型 | 最小値 | 最大値 |
|---|---|---|
| i32 | i32(-2147483648) | 2147483647i |
| i32(-0x80000000) | 0x7fffffffi | |
| u32 | 0u | 4294967295u |
| 0x0u | 0xffffffffu |
注: AbstractInt も整数型です。
6.2.4. 浮動小数点型
f32 型は、 IEEE-754 のbinary32(単精度)形式の 32 ビット浮動小数点値の集合です。 詳細については§ 15.7 浮動小数点評価を参照してください。
f16 型は、
IEEE-754 のbinary16(半精度)形式の
16 ビット浮動小数点値の集合です。プログラムに
f16 拡張を有効にする
enable f16; ディレクティブが含まれていない状態でf16
型を使用すると、シェーダー作成
エラーになります。詳細については§ 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 の いずれかでなければなりません。 |
| atomic<vec2<u32>> |
型 vec2<u32> のアトミック。
この型の値は符号なし64
ビット整数型を表し、下位 32 ビットがベクトル
成分 0 に、上位 32 ビットがベクトル成分 1 に格納されます。
atomic_vec2u_min_max 拡張によって有効になります。 |
式はアトミック型に評価されてはなりません。
アトミック型は、workgroup
アドレス空間内の変数、またはread_write アクセスモードを持つストレージ
バッファー変数によってのみインスタンス化できます。
格納型が
atomic<vec2<u32>> であるかこれを含む場合、その変数はstorage アドレス空間になければなりません。
その型に対する操作のメモリースコープは、
インスタンス化されたアドレス空間によって決まります。
workgroup アドレス空間内のアトミック型は
Workgroup のメモリースコープを持ち、
storage
アドレス空間内のものは QueueFamily のメモリースコープを持ちます。
アトミック 変更とは、アトミックオブジェクトの内容を設定する、そのオブジェクトに対する任意の 操作です。 新しい値がオブジェクトの既存値と同じであっても、その操作は変更として数えられます。
WGSL では、アトミック変更はオブジェクトごとに相互に順序付けられます。 つまり、シェーダーステージの実行中、各アトミックオブジェクト A について、すべての エージェントは A に適用される変更操作の同じ順序を観測します。 異なるアトミックオブジェクトの順序付けは互いに関連しない場合があり、 因果関係は暗示されません。 workgroup 空間の変数は ワークグループ内では共有されますが、 異なるワークグループ間では共有されないことに注意してください。
6.2.9. 配列型
配列は、 インデックス付け可能な要素値のシーケンスです。
| 型 | 説明 |
|---|---|
| array<E,N> | 型 E の要素を N 個持つ固定サイズ
配列。 N を配列の要素数と呼びます。 |
| array<E> | 型 E の要素からなるランタイムサイズ配列。
これらは特定のコンテキストにのみ現れることができます。 |
配列の最初の要素はインデックス 0 にあり、後続の各要素は次の整数インデックスにあります。 § 8.5.3 配列アクセス式を参照してください。
式はランタイムサイズ配列型に評価されてはなりません。
固定サイズ配列の要素数式 N には、次の制約が適用されます:
-
これはoverride 式でなければなりません。
-
N が 0 より大きくない場合:
-
N がconst 式である場合はシェーダー作成エラーです。
-
それ以外の場合はパイプライン作成エラーです。
-
注: N がoverride 宣言に依存する場合、要素数の値はパイプライン作成時に完全に決定され、 それ以外の場合はシェーダーモジュール作成時に完全に決定されます。
注: 型の同値性を満たすには、const 式ではない override 式は識別子でなければなりません。 オーバーライド可能な定数によってサイズ指定される ワークグループ変数を参照してください
ランタイムサイズ配列の要素数は、 対応するストレージバッファー変数に関連付けられた バッファーバインディングのサイズによって決まります。 § 13.3.4 バッファーバインディングによる ランタイムサイズ配列の要素数の決定を参照してください。
配列の要素型は次のいずれかでなければなりません:
-
スカラー型
-
ベクトル型
-
行列型
-
作成時固定フットプリントを持つ配列型
-
作成時固定フットプリントを持つ構造体型。
注: 配列の要素型をbuffer 型にすることはできません。
注: 要素型はプレーン型でなければなりません。
2 つの配列型が同一であるのは、次のすべてが真である場合に限ります:
-
要素型が同じである。
-
要素数の指定が一致する。つまり、次のいずれかが真である:
-
両方ともランタイムサイズである。
-
両方とも作成時固定フットプリントを持つ固定サイズであり、 一方が符号付きで他方が符号なしであっても、要素数の値が等しい。 (要素数は常に正であるため、この場合は符号付き値と符号なし値を 比較できます。)
-
両方とも、同じパイプラインオーバーライド可能定数の宣言に解決される識別子として 要素数が指定された固定サイズである。
-
// array<f32,8> と array<i32,8> は異なる型: // 要素型が異なる var < private> a : array< f32, 8 > ; var < private> b : array< i32, 8 > ; var < private> c : array< i32, 8u > ; // array<i32,8> と array<i32,8u> は同じ型 const width = 8 ; const height = 8 ; // array<i32,8>、array<i32,8u>、array<i32,width> は同じ型。 // それらの要素数は 8 に評価される。 var < private> d : array< i32, width > ; // array<i32,height> と array<i32,width> は同じ型。 var < private> e : array< i32, width > ; var < private> f : array< i32, height > ;
注: オーバーライド可能な定数によってサイズ指定された配列型の 唯一の有効な使用法は、workgroup アドレス空間内のメモリービューとしての使用です。 これには、workgroup 変数の格納型が含まれます。 § 7 変数と値の宣言を参照してください。
override blockSize = 16 ; var < workgroup> odds : array< i32, blockSize > ; var < workgroup> evens : array< i32, blockSize > ; // 同じ型 // 次のどれも 'odds' および 'evens' と同じ型ではない。 // 異なる型: 識別子 'blockSize' ではない var < workgroup> evens_0 : array< i32, 16 > ; // 異なる型: 要素数を表すために算術を使用している。 var < workgroup> evens_1 : array< i32,( blockSize * 2 / 2 ) > ; // 異なる型: 単なる識別子ではなく括弧を使用している。 var < workgroup> evens_2 : array< i32,( blockSize ) > ; // 無効な例。オーバーライド可能な要素数は最外層にのみ現れることができるため。 // var<workgroup> both: array<array<i32,blockSize>,2>; // 無効な例。オーバーライド可能な要素数は // workgroup 変数に対してのみ有効であるため。 // var<private> bad_address_space: array<i32,blockSize>;
6.2.10. 構造体型
構造体は、 名前付きのメンバー値を 名前付きでグループ化したものです。
| 型 | 説明 |
|---|---|
struct AStructName {M1 : T1, ... MN : TN, } |
識別子
AStructName で名前が付けられ、
N 個のメンバーを持つ構造体型の宣言。
メンバー i は識別子 Mi で名前が付けられ、
型は Ti です。
N は少なくとも 1 でなければなりません。 同じ構造体型の 2 つのメンバーが同じ名前を持ってはなりません。 |
構造体型はモジュールスコープで宣言されます。 プログラムソースの他の場所では、構造体型はその識別子名によって表されます。 § 5 宣言とスコープを参照してください。
2 つの構造体型が同一であるのは、それらが同じ名前を持つ場合に限ります。
構造体メンバー型は次のいずれかでなければなりません:
注: 構造体メンバー型をbuffer 型にすることはできません。
注: ユーザー宣言されたすべての構造体型は具象です。
注: 各メンバー型はプレーン型でなければなりません。
構造体メンバー型および配列要素型に対する制限から生じる結果には次のものがあります:
-
ポインター、テクスチャー、またはサンプラーは、配列または構造体内の どのネストレベルにも現れてはなりません。
-
ランタイムサイズ 配列がより大きな型の一部である場合、それは構造体の最後の要素としてのみ現れることができ、 その構造体自体を外側の配列または構造体の一部にすることはできません。
// 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 バッファーまたは storage バッファーの定義に使用する場合に 必要になることがあります。 § 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 について、T のネスト深度を NestDepth(T) と表すと、次のようになります:
-
ベクトル型の場合は 1
-
行列型の場合は 2
-
要素型 E を持つ配列型の場合は 1 + NestDepth(E)
-
T がメンバー型 M1,...,MN を持つ構造体型の場合は 1 + max(NestDepth(M1),..., NestDepth(MN))
6.2.12. 構築可能型
多くの種類の値は、作成、ロード、格納、関数への受け渡し、 および関数からの返却が可能です。 これらを構築可能と呼びます。
型が構築可能であるのは、 次のいずれかである場合です:
注: すべての構築可能型は作成時固定フットプリントを持ちます。
注: アトミック型およびランタイムサイズ配列型は 構築可能ではありません。 アトミックまたはランタイムサイズ配列を含む複合型も構築可能ではありません。
6.2.13. 固定フットプリント型
変数のメモリーフットプリントは、 変数の内容を格納するために使用されるメモリー位置の数です。 変数のメモリーフットプリントはその格納型に依存し、 シェーダーライフサイクルのある時点で確定します。 ほとんどの変数は非常に早い段階、すなわちシェーダー作成時にサイズが決まります。 一部の変数は後のパイプライン作成時にサイズが決まる場合があり、 また他の変数はシェーダー実行開始時までサイズが決まらない場合があります。
型の具象化のサイズが シェーダー作成時に完全に決定される場合、その型は 作成時固定フットプリントを持ちます。
型のサイズがパイプライン作成 時に完全に決定される場合、その型は固定 フットプリントを持ちます。
注: すべての具象の作成時固定フットプリント型および固定フットプリント型は格納可能です。
注: パイプライン作成はシェーダー作成に依存するため、 作成時固定フットプリントを持つ型は固定フットプリントも持ちます。
作成時固定フットプリントを持つ型は次のとおりです:
-
スカラー型
-
ベクトル型
-
行列型
-
次の場合の固定サイズ 配列型:
-
すべてのメンバーが作成時固定フットプリントを持つ構造体型。
-
次の場合の固定サイズ バッファー型:
-
そのサイズがconst 式である。
-
注: 構築可能型は作成時固定フットプリントを持ちます。
固定 フットプリントを持つ型は次のいずれかです:
-
作成時固定フットプリントを持つ型
-
そのサイズをさらに制約しない固定サイズ バッファー型
注: 要素数が const 式ではないoverride 式である固定サイズ配列の唯一の有効な使用法は、 workgroup アドレス空間内のメモリービューとしての使用です。 これには workgroup 変数の格納型が含まれます。
注: 固定フットプリント型はアトミック型を直接または 間接的に含むことができますが、構築可能型は含むことができません。
注: 固定フットプリント型にはランタイムサイズ配列、 ランタイムサイズ バッファー、およびランタイムサイズ配列を含む構造体は含まれません。
6.3. バッファー型
これらの型にはbuffer_view 言語機能が必要です。
buffer 値は、 その内容を別のホスト共有可能型として 解釈できるメモリーを表します。 それ以外では、バッファー値は不透明です。 これは、変数内のデータに複数の異なる型としてアクセスする必要がある場合や、 シェーダー作者が 1 つの変数を複数の論理変数に分割したい場合に役立ちます。
バッファー型は構築可能ではなく、 buffer_view 組み込み関数を介して データを不透明でないホスト共有可能型として解釈した後にのみアクセスできます。
| 型 | 説明 |
|---|---|
| buffer<N> | N バイトのストレージを持つ固定サイズ
バッファー。 N はoverride 式でなければなりません。 |
| buffer | ランタイムサイズバッファー。 |
固定サイズバッファーは、storage、uniform、およびworkgroup アドレス空間の変数によってのみインスタンス化できます。 storage および uniform アドレス空間では、サイズはconst 式でなければなりません。 ランタイムサイズバッファーは storage アドレス空間の変数によってのみインスタンス化できます。
N が 0 より大きくない場合:
-
N がconst 式である場合はシェーダー作成エラーです。
-
それ以外の場合はパイプライン作成エラーです。
f16 拡張が有効で、 N が 2 で割り切れない場合:
-
N がconst 式である場合はシェーダー作成エラーです。
-
それ以外の場合はパイプライン作成エラーです。
f16 拡張が 有効ではなく、N が 4 で割り切れない場合:
-
N がconst 式である場合はシェーダー作成エラーです。
-
それ以外の場合はパイプライン作成エラーです。
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 バッファーおよびstorage バッファー 変数の格納型は ホスト共有可能でなければなりません。
型がホスト共有可能であるのは、 具象であり、かつ 次のいずれかである場合です:
-
行列型
-
作成時固定フットプリントを持ち、その要素型が ホスト共有可能である固定サイズ 配列型
-
その要素型がホスト共有可能であるランタイムサイズ配列 型
-
すべてのメンバーがホスト共有可能である構造体型
注: ステージ間の入力および出力の型に対する制限は、 § 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 は、型 vecN<S> のベクトルへのポインターで、 read_write アクセスモードを持ちます。
-
IndexList = « Idx0, ..., IdxK−1 » は、次を満たすインデックスのシーケンスです:
-
各 Idxi は [0,N−1] の範囲内です。
-
vecK<S> は有効なベクトル型です。つまり、K は {2,3,4} のいずれかです。
-
アルゴリズム: SwizzleViewRead
ポインター p を介して読み取ったベクトルの成分を選択し、任意で並べ替えて形成したベクトルを生成します。
注: スウィズルビューを介した読み取りでは、 一部のベクトル成分が結果に現れない場合でも、ベクトル全体をメモリーから読み取ります。
入力: 型 swizzle<AS,S,N,K> のスウィズル ビュー (p, IndexList)
出力: (p, IndexList) を読み取った結果である、 型 vecK<S> のベクトル値 v。
手順:
慣例により 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 回読み取られ、メモリーへ正確に 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 ); // スウィズルビューに単一文字を適用すると、基礎となるベクトルの // スカラー成分への参照が得られる。 // 次と同じ: v.z = 99; v . yz . y = 99 ; // スウィズルビューをインデックス付けすると、ベクトルの成分の 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 ); // スウィズルビューはポインターから構築できる。 // スウィズルビューに単一文字を適用すると、基礎となるベクトルの // スカラー成分への参照が得られる。 // 次と同じ: (*p).z = 99; p . yz . y = 99 ; // スウィズルビューをインデックス付けすると、ベクトルの成分の 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 バッファーまたはstorage バッファーの場合、 起点変数にバインドされた WebGPU
GPUBufferの任意のメモリー位置からの値 -
起点変数がuniform バッファーまたはstorage バッファーでない場合、 起点変数内の任意のメモリー位置からの値
-
参照の格納型のゼロ値
-
ロードされた値がベクトルの場合、値 (0, 0, 0, x)。ここで x は:
-
整数成分の場合は 0、1、または最大の正の値
-
浮動小数点成分の場合は 0.0 または 1.0
-
-
- 無効な ストア
-
無効な参照へのストアは、次のいずれかを行う場合があります:
-
起点変数がstorage バッファーの場合、 起点変数にバインドされた WebGPU
GPUBufferの任意のメモリー位置に値を格納する -
起点変数がstorage バッファーでない場合、 起点変数内の任意のメモリー位置に値を格納する
-
実行されない。
-
無効なロードまたはストアが、共有アドレス空間内の変数の別の位置へアクセスするよう リダイレクトされた場合、データ競合が発生する可能性があります。 たとえば、同時に実行される複数の呼び出しのアクセスが 配列の最初の要素へリダイレクトされる場合があります。 少なくとも 1 つのアクセスが書き込みであり、それ以外に同期されていない場合、 結果はデータ競合となり、したがって動的エラーになります。
範囲外アクセスは一様性解析の仮定を無効にします。 たとえば、範囲外アクセスによって呼び出しが早期終了した場合、その呼び出しは 集合操作に参加できなくなります。 特に、workgroupBarrier の呼び出しによってシェーダーが停止する場合があり、 微分によって無効な結果が生成される場合があります。
6.5.8. 参照とポインターのユースケース
参照とポインターは、使用方法によって区別されます:
-
変数の型は参照型です。
-
アドレス取得操作 (単項
&)は、参照値を対応するポインター値に変換します。 -
間接参照操作 (単項
*)は、ポインター値を対応する参照値に変換します。 -
let 宣言は ポインター型にできますが、参照型にはできません。
-
仮 引数はポインター型にできますが、参照型にはできません。
-
スウィズルビューは、 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' のメモリーに格納されている 値、すなわち i32 値 0 に評価される。 - 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. 参照値とポインター値の形成
参照値は次のいずれかの方法で形成されます:
-
ポインターに間接参照(単項
*)操作を使用します。 -
複合型へのメモリービュー、 またはスウィズル ビューに名前付き成分式を使用します:
-
ベクトル格納型を持つメモリービュー、またはスウィズルビューに、 単一文字のベクトルアクセス句を追加すると、 ベクトルの名前付き成分への参照が得られます。 § 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. テクスチャーおよびサンプラー型
テクセルは、 テクスチャーの独立してアクセス可能な最小要素として使用されるスカラーまたはベクトルです。 texel という語は texture element の略です。
テクスチャーは、 レンダリングに有用な特殊な操作をサポートするテクセルの集合です。 WGSL では、これらの操作はテクスチャー組み込み関数を介して呼び出されます。 完全な一覧については§ 17.7 テクスチャー組み込み関数を参照してください。
WGSL テクスチャーは WebGPU GPUTexture
に対応します。
テクスチャーには次の特性があります:
- テクセルフォーマット
-
各テクセルのデータ表現。§ 6.6.1 テクセルフォーマットを参照してください。
- 次元数
-
グリッド座標の次元数と、座標がどのように解釈されるか。 次元数は 1、2、または 3 です。 ほとんどのテクスチャーはデカルト座標を使用します。 キューブテクスチャーには 6 つの正方形の面があり、 原点を中心とするキューブに向かう原点からの方向ベクトルとして解釈される 3 次元座標を使用してサンプリングされます。
GPUTextureViewDimensionを参照してください。 - サイズ
-
各次元に沿ったグリッド座標の範囲。これはミップレベルの関数です。
- ミップレベル数
-
ミップレベル数は、サンプリングテクスチャーおよび深度テクスチャーでは少なくとも 1 であり、 ストレージ テクスチャーでは 1 に等しくなります。
ミップレベル 0 は テクスチャーのフルサイズ版を含みます。 後続の各ミップレベルは、前のミップレベルの半分のサイズ(丸めの範囲内)で、 前のミップレベルをフィルタリングした版を含みます。
テクスチャーをサンプリングするときは、明示的または暗黙的に計算された詳細レベルを使用して、 テクセルデータを読み取るミップレベルを選択します。その後、それらを フィルタリングによって組み合わせてサンプリング値を生成します。 - 配列化
-
テクスチャーが配列化されているかどうか。
-
非配列化テクスチャーはテクセルのグリッドです。
-
配列化テクスチャーは、テクセルグリッドの同種配列です。
-
- 配列サイズ
-
テクスチャーが配列化されている場合の同種グリッドの数。
- サンプル数
-
テクスチャーがマルチサンプリングされている場合のサンプル数。
テクスチャー内の各テクセルには一意の論理テクセルアドレスが関連付けられます。 これは次を持つ整数タプルです:
-
次元数によって制御される数の成分。 各成分値は [0, Si) の範囲内であり、Si は i 番目の成分におけるサイズです。
-
テクスチャーが配列化されている場合、 [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> | 不変 | モジュール | 具象ホスト共有可能 | 不可 | はい。 storage バッファー | |
| var<storage, read_write>5,6 | 可変 | モジュール | 具象ホスト共有可能 | 不可 | はい。 storage バッファー | |
| 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 キーワードの後にテンプレートリストとして記述されます:
private、storage、 uniform、workgroup、およびhandle アドレス空間内の変数は、 モジュールスコープでのみ 宣言されなければなりません。一方、function アドレス空間内の変数は、 関数スコープでのみ 宣言されなければなりません。 handle と function を除くすべてのアドレス空間では、アドレス空間を指定しなければなりません。 handle アドレス空間を指定してはなりません。 function アドレス空間の指定は任意です。
アクセスモードには常に 既定値があり、storage アドレス空間内の変数を除き、WGSL ソースで指定してはなりません。 § 14.3 アドレス空間を参照してください。
uniform アドレス空間内の変数は、uniform バッファー変数です。 その格納型は、 ホスト共有可能な構築可能型または 固定サイズバッファー 型でなければならず、 アドレス空間レイアウト制約を満たさなければなりません。
storage アドレス空間内の変数は、storage バッファー変数です。 その格納型は ホスト共有可能型でなければならず、 アドレス空間レイアウト制約を満たさなければなりません。 変数はread またはread_write アクセスモードで宣言できます。既定値は read です。
immediate アドレス空間内の変数は、即時データ変数です。 その格納型は、 配列および配列メンバーを含む構造体を除いた、 ホスト共有可能な構築可能型でなければなりません。 各エントリーポイントは、 最大 1 つの即時データ変数へ静的にアクセスしなければなりません。 immediate 変数の値は、WebGPU API コマンドエンコーダーによって記録された setImmediates コマンドを介して設定され、 シェーダー実行中は一定のままです。 変数のサイズは、パイプラインレイアウトのimmediateSize 設定によって制限されます。
テクスチャーリソースは、 実効値型がテクスチャー型である変数です。 これはモジュールスコープで宣言されます。 基礎となるテクスチャー内の テクセルのグリッドへアクセスするために使用される 不透明ハンドルを保持します。 ハンドル自体はhandle アドレス空間にあり、常に読み取り専用です。 多くの場合、基礎となるテクセルは読み取り専用であり、テクスチャー変数は不変であるといいます。 書き込み専用ストレージテクスチャーおよび読み書き可能ストレージ テクスチャーでは、基礎となるテクセルは可変であり、慣例により テクスチャー変数は可変であるといいます。
サンプラーリソースは、 実効値型がサンプラー型である変数です。 これはモジュールスコープで宣言され、 handle アドレス空間に存在し、 不変です。
§ 13.3.2 リソースインターフェイスで説明されるように、uniform バッファー、storage バッファー、 テクスチャー、およびサンプラーはシェーダーのリソースインターフェイスを形成します。
変数の存続期間は、 シェーダー実行中にメモリー位置が変数に関連付けられている期間です。 モジュールスコープ 変数の存続期間は、シェーダーステージの実行全体です。 各呼び出しについて、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 バッファー // 読み書き用の storage バッファー @group ( 0 ) @binding ( 0 ) var < storage, read_write> pbuf : array< vec2< f32>> ; // テクスチャーとサンプラーは常に "handle" 空間にある。 @group ( 0 ) @binding ( 1 ) var filter_params : sampler;
// Storage バッファー @group ( 0 ) @binding ( 0 ) var < storage, read> buf1 : Buffer ; // 読み取り可能、書き込み不可。 @group ( 0 ) @binding ( 0 ) var < storage> buf2 : Buffer ; // 読み取り可能、書き込み不可。 @group ( 0 ) @binding ( 1 ) var < storage, read_write> buf3 : Buffer ; // 読み取りと書き込みの両方が可能。 struct ParamsTable { weight : f32} // Uniform バッファー。常に読み取り専用で、より厳しいレイアウト規則を持つ。 @group ( 0 ) @binding ( 2 ) var < uniform> params : ParamsTable ; // 読み取り可能、書き込み不可。
fn f () { var < function> count : u32; // function アドレス空間内の変数。 var delta : i32; // function アドレス空間内の別の変数。 var sum : f32= 0.0 ; // 初期化子を持つ function アドレス空間変数。 var pi = 3.14159 ; // 初期化子から f32 格納型を推論する。 }
7.4. 変数宣言と値宣言の文法概要
| variable_decl '=' expression
| 'let' optionally_typed_ident '=' expression
| 'const' optionally_typed_ident '=' expression
'var' _disambiguate_template template_list ? optionally_typed_ident
ident ( ':' type_specifier ) ?
attribute * variable_decl ( '=' expression ) ?
'const' optionally_typed_ident '=' expression
| attribute * 'override' optionally_typed_ident ( '=' expression ) ?
8. 式
式は、値がどのように 計算されるかを指定します。
さまざまな種類の値式は、いつ評価されるかと、どの程度表現力を持てるかの間で トレードオフを提供します。 評価が早いほど操作はより制約されますが、その一方で 値を使用できる場所は増えます。このトレードオフにより、値宣言の種類ごとに 異なる柔軟性が生じます。 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 が評価され、かつ OuterE の評価に E の評価が必要である、
-
E が式 OuterE の部分式であり、 OuterE がシェーダー作成エラーを生成するために E の評価を必要とする (例: 整数除算)。
注: この評価規則は、短絡評価
演算子 && および || が、静的型を決定するために評価を必要とする部分式がない限り、
右辺の部分式の評価を抑制することを意味します。
const 式は、WebGPU API メソッドを実装する CPU によって評価される場合があります。 したがって、AbstractFloat 値に対する操作の精度要件は、WebAssembly [WASM-CORE-2] や ECMAScript [ECMASCRIPT] など、 一般的な WebGPU ランタイム環境で要求されるものより厳しくありません。 具象浮動小数点型(f32 など)の精度要件は、§ 15.7.4.1 具象浮動小数点式の精度で指定されます。
例: (42) は次のように解析されます:
-
42という項はAbstractInt 値 42 です。 -
その項を括弧で囲むと、値 42 を持つ AbstractInt 型の 新しい式
(42)が生成されます。
例: -5 は次のように解析されます:
-
5という項はAbstractInt 値 5 です。 -
その項の前に '
-' を付けると、値 -5 を持つ AbstractInt 型の 新しい式-5が生成されます。
例: -2147483648 は次のように解析されます:
-
2147483648という項はAbstractInt 値 2147483648 です。 この値は 32 ビット符号付き整数には収まらないことに注意してください。 -
その項の前に '
-' を付けると、値 -2147483648 を持つ AbstractInt 型の 新しい式-2147483648が生成されます。
例: const minint = -2147483648; は次のように解析されます:
-
上記のとおり、
-2147483648はAbstractInt 値 -2147483648 に評価されます。 -
結果として、
minintはAbstractInt 値 -2147483648 として宣言されます。
例: let minint = -2147483648; は次のように解析されます:
-
上記のとおり、
-2147483648はAbstractInt 値 -2147483648 に評価されます。 -
let 宣言には明示的な型がないため、オーバーロード解決が使用されます。 適用可能なオーバーロード候補は、AbstractInt からi32、u32、またはf32 への実行可能な自動変換を使用します。 最もランクが低いものはi32 への変換であるため、 AbstractInt 値 -2147483648 は i32 値 -2147483648 に変換されます。
-
結果として、
minintは i32 値 -2147483648 として宣言されます。
例: false && (10i < i32(5 * 1000 * 1000 * 1000)) は次のように解析されます:
-
式全体は const 式です。
-
ただし、
&&演算子の短絡評価規則が適用されます: 左辺は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という項はAbstractInt 値 42 です。 -
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 が 0 以外の値にオーバーライドされる場合、エラーは発生しない。 // * 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])、または -
スウィズル名を使用する。 これは、各文字が元のベクトルの成分に対応する便宜的な名前の列として記述される コンテキスト依存名です。
-
色用の便宜的な名前の集合:
r、g、b、aは、それぞれベクトル成分 0、1、2、3 に対応します。 -
次元用の便宜的な名前の集合:
x、y、z、wは、それぞれベクトル成分 0、1、2、3 に対応します。
-
便宜的な名前には . 記法を使用してアクセスします。(例: color.bgra)。
便宜的な文字体系を混在させてはなりません。たとえば、
.rybw は使用できません。
便宜的な文字でベクトルの末尾を超えた成分にアクセスしてはなりません。
便宜的な文字は、必要に応じて文字を重複させることも含め、任意の順序で適用できます。 指定する文字数は 1 以上 4 以下でなければなりません。 つまり、便宜的な文字を使用して生成できるのは、スカラー型または有効なベクトル型だけです。
結果の型は、指定された文字数に依存します。vec4<f32> を想定すると:
| アクセサー | 結果の型 |
|---|---|
| r | f32
|
| rg | vec2<f32>
|
| rgb | vec3<f32>
|
| rgba | vec4<f32>
|
var a : vec3< f32> = vec3< f32> ( 1. , 2. , 3. ); var b : f32= a . y ; // b = 2.0 var c : vec2< f32> = a . bb ; // c = (3.0, 3.0) var d : vec3< f32> = a . zyx ; // d = (3.0, 2.0, 1.0) var e : f32= a [ 1 ]; // e = 2.0
8.5.1.1. ベクトルの単一成分選択
| 前提条件 | 結論 | 説明 |
|---|---|---|
| e: vecN<T> |
e.x: Te .r: T
|
e の最初の成分を選択します
これは単一文字のスウィズルです。 |
| e: vecN<T> |
e.y: Te .g: T
|
e の 2 番目の成分を選択します
これは単一文字のスウィズルです。 |
| e: vecN<T> N は 3 または 4 |
e.z: Te .b: T
|
e の 3 番目の成分を選択します
これは単一文字のスウィズルです。 |
| e: vec4<T> |
e.w: Te .a: T
|
e の 4 番目の成分を選択します
これは単一文字のスウィズルです。 |
| 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.IJ を計算します。ここで e は評価時に
pr が参照するメモリー位置に格納されているベクトルです。
文字 |
|
swizzle_assignment はサポートされていない
pr: ref<AS,vecN<T,AM>> または
ptr<AS,vecN<T,AM>> |
pr.IJ: vec2<T> |
e.IJ を計算します。ここで e は評価時に
pr が参照するメモリー位置に格納されているベクトルです。
文字 |
|
swizzle_assignment はサポートされていない
pr: ref<AS,vecN<T,AM>> または
ptr<AS,vecN<T,AM>> |
pr.IJK: vec3<T> |
e.IJK を計算します。ここで e は
評価時に pr が参照するメモリー位置に格納されているベクトルです。
文字 |
|
swizzle_assignment はサポートされていない
pr: ref<AS,vecN<T,AM>> または
ptr<AS,vecN<T,AM>> |
pr.IJK: vec3<T> |
e.IJK を計算します。ここで e は
評価時に pr が参照するメモリー位置に格納されているベクトルです。
文字 |
|
swizzle_assignment はサポートされていない
pr: ref<AS,vecN<T,AM>> または
ptr<AS,vecN<T,AM>> |
pr.IJKL:
vec4<T> |
e.IJKL を計算します。ここで e は
評価時に pr が参照するメモリー位置に格納されているベクトルです。
文字 |
|
swizzle_assignment はサポートされていない
pr: ref<AS,vecN<T,AM>> または
ptr<AS,vecN<T,AM>> |
pr.IJKL:
vec4<T> |
e.IJKL を計算します。ここで e は
評価時に pr が参照するメモリー位置に格納されているベクトルです。
文字 |
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 が参照するベクトルの最初の成分への参照を計算します。 結果の参照の起点変数は、 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
| 短絡評価の「or」。e1 または e2 のいずれかが
true の場合に true を生成します。
e1 が false の場合にのみ e2 を評価します。
|
| e1: bool e2: bool | e1 && e2: bool
| 短絡評価の「and」。e1 と e2 の両方が
true の場合に true を生成します。
e1 が true の場合にのみ e2 を評価します。
|
| e1: T e2: T T は bool または vecN<bool> | e1 | e2: T
| 論理「or」。T がベクトルの場合は成分ごとです。e1 と e2 の両方を評価します。 |
| e1: T e2: T T は bool または vecN<bool> | e1 & e2: T
| 論理「and」。T がベクトルの場合は成分ごとです。e1 と e2 の両方を評価します。 |
8.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 回ずつ評価し、次のように評価されます:
注: 0 でない場合、結果は 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 を左へシフトし、最下位位置に 0 ビットを挿入し、 最上位ビットを破棄します。 シフトするビット数は e2 の値を e1 のビット幅で剰余した値です。
e1 と e2 の両方がシェーダー実行 開始前に既知である場合、 結果はオーバーフローしてはなりません:
T がベクトルの場合は成分ごとです。 |
| e1: T e2: TS T は AbstractInt または vecN<AbstractInt> T が AbstractInt の場合、TS は u32、それ以外の場合 TS は vecN<u32> | e1 << e2: T
|
左シフト(シフトされる値は抽象):
e1 を左へシフトし、最下位位置に 0 ビットを挿入し、 最上位ビットを破棄します。 シフトするビット数は 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 が符号なし型の場合、最上位位置に 0 ビットを挿入します。 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 個以上の文のシーケンスです。 宣言がそれらの文の 1 つである場合、その識別子は 次の文の開始から複合文の終端までスコープ内です。
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 の最初の成分に 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) と同じ |
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 節の集合の 1 つ、 または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'
トークンは、単一のcase_selector リスト内に 2 回以上現れてはなりません。
型規則の 前提条件: 単一の switch 文について、セレクター式とすべての case セレクター式は、同じ具象整数スカラー型でなければなりません。
case_selectors 内の式はconst 式でなければなりません。
同じ switch 文内の異なる 2 つの case セレクター式は、同じ値を持ってはなりません。
セレクター値がcase_selector リスト内の式の値と等しい場合、 制御はそのcase 節の本体へ移ります。 セレクター値がどの case セレクター値とも等しくない場合、制御は default 節の本体へ移ります。
制御が節の本体の終端に到達すると、switch 文の直後の最初の文へ制御が移ります。
節の本体内の文の 1 つが宣言である場合、 それは複合文内の宣言に関する通常のスコープおよび存続期間の規則に従います。 つまり、本体は文のシーケンスであり、その 1 つが宣言である場合、 その宣言のスコープはシーケンス内の次の文の開始から 本体の終端まで続きます。 宣言は到達したときに実行され、 変数または値の新しいインスタンスを作成して初期化します。
var a : i32; let x : i32= generateValue (); switch x { case 0 : { // コロンは任意 a = 1 ; } default { // default は最後に現れる必要はない a = 2 ; } case 1 , 2 , { // 複数のセレクター値を使用できる a = 3 ; } case 3 , { // 末尾のカンマは任意 a = 4 ; } case 4 { a = 5 ; } }
const c = 2 ; var a : i32; let x : i32= generateValue (); switch x { case 0 : { a = 1 ; } case 1 , c { // const 式を case セレクターで使用できる a = 3 ; } case 3 , default { // default キーワードは他の節とともに使用できる a = 4 ; } }
9.4.3. Loop 文
loop 文はループ本体を繰り返し実行します。 ループ本体は複合文として指定されます。 ループ本体の各実行を反復と呼びます。
この繰り返しは、break 文または return 文によって中断できます。
任意で、ループ本体の最後の文を continuing 文にできます。
loop が 無制限の数の反復を実行することになる場合、 動的エラーが発生します。 これによりループの早期終了、その他の非局所的な影響、さらにはデバイスロスが発生する場合があります。
ループ本体内の文の 1 つが宣言である場合、 それは複合文内の宣言に関する通常のスコープおよび存続期間の規則に従います。 つまり、ループ本体は文のシーケンスであり、その 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 文は次の形式の loop に脱糖されます:
{条件式が存在しない場合、
initializer ;
loop {
if !(condition) { break; }
body
continuing { update_part }
}
}
for 文は次の形式の loop に脱糖されます:
{
initializer ;
loop {
body
continuing { update_part }
}
}
さらに:
-
initializerが空でない場合、最初の反復より前に追加のスコープ内で実行されます。 初期化子内の宣言のスコープは、ループ本体の終端まで続きます。 -
型 規則の前提条件: 条件が空でない場合、それはbool 型の式でなければなりません。
-
存在する場合、条件は for ループ本体を実行する直前に評価されます。 条件が false の場合、§ 9.4.6 Break 文が 実行され、ループの実行を終了します。 この検査は各ループ反復の開始時に実行されます。
-
-
update_partが空でない場合、ループ構文の末尾にあるcontinuing 文になります。 -
脱糖では、
update_part内のすべての識別子が 脱糖前と同じ宣言へ解決されることを保証するため、必要に応じてbody内で宣言された識別子の名前を変更します。
for ループの initializer は、ループの実行前に 1 回実行されます。
宣言が
初期化子に現れる場合、その識別子は 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 ループは実行を終了します。 それ以外の場合、反復の残りが実行されます。
型規則の 前提条件: 条件はbool 型でなければなりません。
while ループは、loop 文またはfor 文のいずれかに対する構文糖とみなすことができます。 次の文形式は等価です:
-
whilecondition{body_statements} -
loop { if !condition{break;}body_statements} -
for (;condition;) {body_statements}
while ループが 無制限の数の反復を実行することになる場合、 動的エラーが発生します。 これにより、ループの早期終了、その他の非局所的な影響、さらにはデバイスロスが発生する場合があります。
9.4.6. Break 文
'break'
break 文は、最も近くにある外側のループ本体 またはswitch 文の直後へ 制御を移し、ループまたは switch 文の実行を終了します。
break 文は、loop、for、while、およびswitch 文内でのみ使用しなければなりません。
break 文は、ループのcontinuing 文から
抜けることになる位置に配置してはなりません。
代わりにbreak-if 文を使用してください。
var a : i32= 2 ; var i : i32= 0 ; loop { let step : i32= 1 ; if i % 2 == 0 { continue ; } a = a * 2 ; continuing { i = i + step ; if i >= 4 { break ; } // 無効。代わりに break-if を使用する。 } }
9.4.7. Break-If 文
'break' 'if' expression ';'
break-if 文はブール条件を評価します。 条件が true の場合、制御は最も近くにある外側のloop 文の本体の直後へ移り、そのループの実行を終了します。
型規則の 前提条件: 条件はbool 型でなければなりません。
注: break-if 文は、 continuing 文の本体内の最後の 文としてのみ現れることができます。
var a : i32= 2 ; var i : i32= 0 ; loop { let step : i32= 1 ; if i % 2 == 0 { continue ; } a = a * 2 ; continuing { i = i + step ; break if i >= 4 ; } }
9.4.8. Continue 文
'continue'
continue 文は、最も近くにある外側のloop 内で制御を移します:
-
存在する場合、そのループ本体の末尾にあるcontinuing 文へ前方に移します。
-
それ以外の場合、ループ本体の最初の文へ後方に移し、次の反復を開始します。
continue 文は、loop、for、またはwhile 文内でのみ使用しなければなりません。
continue 文は、外側のcontinuing 文へ制御を移すことになる位置に配置してはなりません。
(continuing 文へ分岐する場合、それは前方分岐です。)
continue 文は、対象のcontinuing 文で使用される宣言を越えて
制御を移すことになる位置に配置してはなりません。
注: continue は、
continuing 文内にネストされた別のループの内部で制御フローを移すために使用する場合に限り、
continuing 文内で使用できます。つまり、continue を使用して
現在実行中の continuing 文の先頭へ制御を移すことはできません。
var i : i32= 0 ; loop { if i >= 4 { break ; } if i % 2 == 0 { continue ; } // <3> let step : i32= 2 ; continuing { i = i + step ; } }
-
<3>
continueは、continuing構文で使用されるstepの宣言を迂回するため無効です
9.4.9. Continuing 文
'continuing' continuing_compound_statement
continuing 文は、ループ反復の終端で実行される複合文を指定します。 この構文は任意です。
複合文は、どの複合文のネストレベルにおいてもreturn を含んではなりません。
9.4.10. Return 文
'return' expression ?
return 文は現在の関数の実行を終了します。 関数がエントリーポイントである場合、 現在のシェーダー呼び出しが 終了します。 それ以外の場合、現在の関数呼び出しの呼び出しサイトの評価後にある 次の式または文から評価を続行します。
関数に戻り値の 型がない場合、return 文は 任意です。そのような関数で return 文を指定する場合、値を指定してはなりません。 それ以外の場合、式が存在しなければならず、これを戻り値と呼びます。 この場合、この関数呼び出しの呼び出しサイトは戻り値に評価されます。 戻り値の型は関数の戻り値の型と一致しなければなりません。
9.4.11. Discard 文
discard 文は呼び出しを
ヘルパー呼び出しに変換し、
フラグメント出力を破棄します。
discard 文はフラグメントシェーダーステージでのみ使用しなければなりません。
より正確には、discard 文を実行すると次のことが行われます:
-
現在の呼び出しをヘルパー呼び出しに変換し、かつ
-
現在のフラグメント出力がGPURenderPipelineの下流で処理されるのを防ぎます。
discard 文より前に実行された文だけが観測可能な効果を持ちます。
注: discard 文は
フラグメントステージ内の関数のいずれからでも実行でき、その効果は同じです:
フラグメント出力は破棄されます。
@group ( 0 ) @binding ( 0 ) var < storage, read_write> will_emit_color : u32; fn discard_if_shallow ( pos : vec4< f32> ) { if pos . z < 0.001 { // これが実行された場合、ヘルパー呼び出しは共有メモリーへ // 書き込まないため、will_emit_color 変数が 1 に設定されることは // ない。 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} } } // 動作: {Next}。switch が Break を Next に置き換えるため a = 5 ; // 有効。前の文の動作に Next が含まれていたため }
fn invalid_infinite_loop () { loop { discard ; // 動作 { Next }。 } // 無効。ループ全体の動作は { }。 }
fn conditional_continue () { var a : i32; loop { if a == 5 { break ; } // 動作: {Break, Next} if a % 2 == 1 { // 有効。前の文の動作に Next が含まれるため continue ; // 動作: {Continue} } // 動作: {Continue, Next} a = a * 2 ; // 有効。前の文の動作に Next が含まれるため continuing { // continuing 文の動作が {Next} なので有効 // 次のいずれも含まない: // {Break, Continue, Return} a = a + 1 ; } } // ループ全体の動作は {Next}、 // "Continue" と "Next" を吸収し、 // その後 "Break" を "Next" に置き換えるため }
fn redundant_continue_with_continuing () { var a : i32; loop { if a == 5 { break ; } continue ; // 有効。これは冗長で、次の文へ分岐する。 continuing { a = a + 1 ; } } }
fn continue_end_of_loop_body () { for ( var i : i32= 0 ; i < 5 ; i ++ ) { continue ; // 有効。これは冗長で、 // ループ本体の末尾へ分岐する。 } // 動作: {Next}、 // ループが "Continue" を吸収し、 // "for" ループは常に "Next" を追加するため }
for ループは、条件付き 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
型規則の 前提条件: 式はbool 型でなければなりません。
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 関数を宣言する。 // 2 つの仮引数 i と b を持つ。 // 戻り値の型は 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. 関数の制限
-
頂点シェーダーはposition 組み込み 出力値を返さなければなりません。
-
エントリーポイントは関数呼び出しの対象に決してなってはなりません。
-
-
構築可能型
-
ポインター型
-
テクスチャー型
-
サンプラー型
-
-
各関数呼び出し引数は、対応する関数パラメーターの型に評価されなければなりません。
-
特に、ポインターである引数は、仮引数とアドレス 空間、格納 型、およびアクセスモードについて一致しなければなりません。
-
注: あらゆる種類の宣言間で循環が許可されないため、 再帰は禁止されています。
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 ); // 無効。同じルート識別子を持つ 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
属性の説明で明示的に許可されていない限り、属性はオブジェクトまたは型ごとに 2 回以上指定してはなりません。
12.1. align
'@' 'align' '(' expression ',' ?
')'
| 説明 |
メモリー内での構造体メンバーの配置を制約します。
構造体型のメンバーにのみ適用しなければなりません。 この属性は、包含する構造体型の値がメモリー内にどのように現れるかに影響します: 構造体自体とその構成メンバーが現れることのできるバイトアドレスを 制約します。 align(n) が型 T を持つ S のメンバーに
適用され、
S がアドレス空間 AS 内の変数の格納型になり得て、
AS がuniform でない場合、
n は次を満たさなければなりません:
n = k × RequiredAlignOf(T,AS) となる正の整数 k が存在する。 アラインメントとサイズの規則は相互再帰的です。 ただし、上記の制約はネストされた型の必要アラインメントに依存し、 型には有限のネスト深度があるため、適切に定義されています。 uniform または storage バッファーにバインドされたメモリーの開始アドレスのアラインメントが 属性で指定された値より低い場合、結果のアラインメントは その 2 つの最小値になります。 実装は変数のベースアドレスを基準としてのみ 属性を満たします。 § 14.4 メモリーレイアウトを参照してください。 |
| パラメーター | i32 またはu32 に解決されるconst 式でなければなりません。 正でなければなりません。 2 のべき乗でなければなりません。 |
12.2. binding
'@' 'binding' '(' expression ',' ?
')'
| 説明 |
バインドグループ内のリソースのバインディング番号を指定します。
§ 13.3.2 リソースインターフェイスを参照してください。
リソース変数にのみ適用しなければなりません。 |
| パラメーター | i32 またはu32 に解決されるconst 式でなければなりません。 0 以上でなければなりません。 |
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
診断を参照してください。
構文形式には複数のdiagnostic 属性を指定できますが、 それらは異なるトリガールールを指定しなければなりません。 |
| パラメーター |
最初のパラメーターはseverity_control_name です。
2 番目のパラメーターは、トリガールールを指定するdiagnostic_rule_name トークンです。 |
12.7. group
'@' 'group' '(' expression ',' ?
')'
| 説明 |
リソースのバインディンググループを指定します。
§ 13.3.2 リソースインターフェイスを参照してください。
リソース変数にのみ適用しなければなりません。 |
| パラメーター | i32 またはu32 に解決されるconst 式でなければなりません。 0 以上でなければなりません。 |
12.8. id
'@' 'id' '(' expression ',' ?
')'
| 説明 | パイプラインでオーバーライド可能な定数の代替名として 数値識別子を指定します。 |
| パラメーター | i32 またはu32 に解決されるconst 式でなければなりません。 0 以上でなければなりません。 |
12.9. interpolate
'@' 'interpolate' '(' interpolate_type_name ',' ? ')'
| '@' 'interpolate' '(' interpolate_type_name ',' interpolate_sampling_name ',' ? ')'
| 説明 |
ユーザー定義 IO をどのように補間しなければならないかを指定します。
§ 13.3.1.4 補間を参照してください。
location 属性が適用された宣言にのみ適用しなければなりません。 |
| パラメーター |
最初のパラメーターは、補間型の
補間型名トークンでなければなりません。
2 番目のパラメーターが存在する場合、補間サンプリングの 補間サンプリング名トークンでなければなりません。 |
12.10. invariant
'@' 'invariant'
| 説明 |
頂点
シェーダーのposition 組み込み出力値に
適用すると、結果の計算は異なる
プログラム間、および同じエントリーポイントの異なる呼び出し間で不変になります。
つまり、異なるエントリーポイント内の 2 つの position 出力について
データフローと制御フローが一致する場合、結果の値が同じであることが
保証されます。
position 組み込み入力値には影響しません。
position 組み込み値にのみ適用しなければなりません。 注: この属性は HLSL の
|
| パラメーター | なし |
12.11. location
'@' 'location' '(' expression ',' ?
')'
| 説明 |
エントリーポイントのユーザー定義 IO の一部を指定します。
§ 13.3.1.3 入出力ロケーションを参照してください。
エントリーポイント関数のパラメーター、エントリーポイントの 戻り値の型、または構造体型のメンバーにのみ適用しなければなりません。 数値スカラー または数値 ベクトル型のオブジェクトの宣言にのみ適用しなければなりません。 コンピュートシェーダー ステージ入力に含めてはなりません。 |
| パラメーター | i32 またはu32 に解決されるconst 式でなければなりません。 0 以上でなければなりません。 |
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 次元を指定します。
最初のパラメーターは x 次元を指定します。 2 番目のパラメーターが指定されている場合は y 次元を指定し、指定されていない場合は 1 とみなされます。 3 番目のパラメーターが指定されている場合は z 次元を指定し、指定されていない場合は 1 とみなされます。 コンピュートシェーダーのエントリーポイント関数にのみ適用しなければなりません。 その他のオブジェクトには適用してはなりません。 |
| パラメーター |
1 個、2 個、または 3 個のパラメーターを取ります。
各パラメーターはconst 式またはoverride 式でなければなりません。 すべてのパラメーターは、i32 またはu32 のいずれかの同じ型でなければなりません。 指定されたパラメーターのいずれかが、0 以下の値に評価される const 式である場合、シェーダー作成エラーになります。 指定されたパラメーターのいずれかが 0 以下の値に評価される、 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 つのシェーダー ステージを定義します:
-
compute
-
vertex
-
fragment
各シェーダーステージには、別の箇所で説明される独自の機能と制約があります。
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 宣言。
-
上記のいずれかにある任意の属性。
これで、シェーダーのインターフェイスを次で構成されるものとして正確に定義できます:
-
エントリーポイントの戻り値。 これはシェーダーステージ出力を表します。
-
シェーダーによって静的に アクセスされるuniform バッファー、 storage バッファー、テクスチャー リソース、およびサンプラーリソース変数。
-
シェーダーによって 静的に アクセスされるoverride 宣言。
-
シェーダーによって 静的に アクセスされる即時データ 変数。
13.3.1. ステージ間入出力インターフェイス
シェーダーステージ入力 は、パイプラインの上流からシェーダーステージに提供されるデータです。 各データは組み込み入力値またはユーザー定義入力のいずれかです。
シェーダーステージ 出力は、パイプライン下流の後続処理にシェーダーが提供するデータです。 各データは組み込み出力値またはユーザー定義出力のいずれかです。
IO 属性は、 オブジェクトをシェーダーステージ入力またはシェーダーステージ出力として確立するため、 または入力や出力のプロパティをさらに記述するために使用されます。 IO 属性は次のとおりです:
13.3.1.1. 組み込み入力と出力
組み込み入力 値は、システムが生成した制御情報へのアクセスを提供します。 エントリーポイントは、同じ組み込み 値名を持つ 2 つの組み込み入力を持ってはなりません。
名前 X、型 TX を持つステージ S の組み込み入力には、 シェーダーステージ S の エントリーポイントの仮引数を介して、 次の 2 つの方法のいずれかでアクセスします:
-
パラメーターが属性
builtin(X)を持ち、型が TX である。 -
パラメーターが構造体型を持ち、その構造体メンバーの 1 つが属性
builtin(X)を持ち、型が TX である。
逆に、エントリーポイントのパラメーターまたはパラメーターのメンバーがbuiltin 属性を持つ場合、 対応する builtin はエントリーポイントのシェーダーステージの入力でなければなりません。
組み込み出力 値は、シェーダーがパイプライン内の後続処理段階へ 制御情報を伝えるために使用されます。 エントリーポイントは、同じ組み込み 値名を持つ 2 つの組み込み出力を持ってはなりません。
名前 Y、型 TY を持つステージ S の組み込み出力は、 シェーダーステージ S の エントリーポイントの戻り値を介して、次の 2 つの方法のいずれかで設定されます:
-
エントリーポイントの戻り値の型 が属性
builtin(Y)を持ち、型が TY である。 -
エントリーポイントの戻り値の 型が構造体型を持ち、その構造体メンバーの 1 つが属性
builtin(Y)を持ち、型が TY である。
逆に、エントリーポイントの戻り値の型または戻り値の型のメンバーがbuiltin 属性を持つ場合、 対応する builtin はエントリーポイントのシェーダーステージの出力でなければなりません。
注: position 組み込み値は、 頂点シェーダーの出力であると同時に、フラグメントシェーダーへの入力でもあります。
組み込み入力値と組み込み出力値を総称して組み込み値と呼びます。
次の表は、利用可能な組み込み値をまとめたものです。 各項目は組み込み値の組み込み値名トークンです。 各項目については後続の節で詳しく説明します。
| 名前 | ステージ | 方向 | 型 | 拡張 |
|---|---|---|---|---|
| vertex_index | vertex | input | u32 | |
| instance_index | vertex | input | u32 | |
| clip_distances | vertex | output | array<f32, N> (N ≤ 8)
| clip_distances |
| position | vertex | output | vec4<f32> | |
| fragment | input | vec4<f32> | ||
| front_facing | fragment | input | bool | |
| frag_depth | fragment | output | f32 | |
| primitive_index | fragment | input | u32 | primitive_index |
| sample_index | fragment | input | u32 | |
| sample_mask | fragment | input | u32 | |
| fragment | output | u32 | ||
| local_invocation_id | compute | input | vec3<u32> | |
| local_invocation_index | compute | input | u32 | |
| global_invocation_id | compute | input | vec3<u32> | |
| global_invocation_index | compute | input | u32 | linear_indexing |
| workgroup_id | compute | input | vec3<u32> | |
| workgroup_index | compute | input | u32 | linear_indexing |
| num_workgroups | compute | input | vec3<u32> | |
| subgroup_invocation_id | compute | input | u32 | subgroups |
| fragment | ||||
| subgroup_size | compute | input | u32 | subgroups |
| fragment | ||||
| subgroup_id | compute | input | u32 | subgroups and subgroup_id |
| num_subgroups | compute | input | u32 | subgroups and subgroup_id |
struct VertexOutput { @builtin ( position) my_pos : vec4< f32> , @builtin ( clip_distances ) my_clip_distances : array< f32, 8 > , } @vertex fn vs_main ( @builtin ( vertex_index) my_index : u32, @builtin ( instance_index) my_inst_index : u32, ) -> VertexOutput {} struct FragmentOutput { @builtin ( frag_depth) depth : f32, @builtin ( sample_mask) mask_out : u32} @fragment fn fs_main ( @builtin ( front_facing) is_front : bool, @builtin ( position) coord : vec4< f32> , @builtin ( sample_index) my_sample_index : u32, @builtin ( sample_mask) mask_in : u32, ) -> FragmentOutput {} @compute @workgroup_size ( 64 ) fn cs_main ( @builtin ( local_invocation_id) local_id : vec3< u32> , @builtin ( local_invocation_index) local_index : u32, @builtin ( global_invocation_id) global_id : vec3< u32> , ) {}
13.3.1.1.1. clip_distances
| 名前 | clip_distances |
| ステージ | vertex |
| 型 | array<f32, N> |
| 方向 | 出力 |
| 説明 |
配列内の各値は、ユーザー定義クリップ平面までの距離を表します。クリップ距離が
0 の場合、頂点は平面上にあり、正の距離は頂点がクリップ
半空間の内側にあることを、負の距離は頂点がクリップ半空間の外側にあることを意味します。clip_distances の配列
サイズは ≤ 8 でなければなりません。
WebGPU § 23.2.4
プリミティブクリッピングを参照してください。
|
13.3.1.1.2. frag_depth
| 名前 | frag_depth |
| ステージ | fragment |
| 型 | f32 |
| 方向 | 出力 |
| 説明 |
ビューポート深度範囲内の、更新されたフラグメント深度。
WebGPU § 3.3 座標系を参照してください。 fragment_depth 機能がサポートされている場合、 builtin 属性には、深度モードを指定するための任意の 2 番目の パラメーターを指定できます:
フラグメントの元の深度は、そのフラグメントの RasterizationPoint の depth プロパティです。 シェーダーが深度モードの約束に違反する深度値を返した場合、代わりに 不定の深度値が使用されることがあります。
|
13.3.1.1.3. front_facing
| 名前 | front_facing |
| ステージ | fragment |
| 型 | bool |
| 方向 | 入力 |
| 説明 | 現在のフラグメントが前面プリミティブ上にある場合は True。 それ以外の場合は False。 |
13.3.1.1.4. global_invocation_id
| 名前 | global_invocation_id |
| ステージ | compute |
| 型 | vec3<u32> |
| 方向 | 入力 |
| 説明 | 現在の呼び出しのグローバル呼び出し ID、すなわち コンピュート シェーダーグリッド内での位置です。global_invocation_id の値は、 workgroup_id * workgroup_size + local_invocation_id に等しくなります。 |
13.3.1.1.5. global_invocation_index
| 名前 | global_invocation_index |
| ステージ | compute |
| 型 | u32; |
| 方向 | 入力 |
| 説明 |
現在の呼び出しのグローバル呼び出しインデックス、すなわち
コンピュートシェーダーグリッド内での線形位置です。global_invocation_index
の値は次に等しくなります:
global_invocation_id.x +
注: ディスパッチされる
ワークグループ数によってこの値がu32
型の範囲を超える場合、ディスパッチは失敗します:
|
13.3.1.1.6. instance_index
| 名前 | instance_index |
| ステージ | vertex |
| 型 | u32 |
| 方向 | 入力 |
| 説明 |
現在の API レベルの描画コマンド内における現在の頂点のインスタンスインデックス。
最初のインスタンスのインデックスは、直接指定されたか間接的に指定されたかにかかわらず、
描画の |
13.3.1.1.7. local_invocation_id
| 名前 | local_invocation_id |
| ステージ | compute |
| 型 | vec3<u32> |
| 方向 | 入力 |
| 説明 | 現在の呼び出しのローカル呼び出し ID、すなわち ワークグループ グリッド内での位置です。 |
13.3.1.1.8. local_invocation_index
| 名前 | local_invocation_index |
| ステージ | compute |
| 型 | u32 |
| 方向 | 入力 |
| 説明 | 現在の呼び出しのローカル呼び出しインデックスであり、 ワークグループグリッド内における呼び出しの位置を線形化したインデックスです。 |
13.3.1.1.9. num_workgroups
| 名前 | num_workgroups |
| ステージ | compute |
| 型 | vec3<u32> |
| 方向 | 入力 |
| 説明 |
API によってディスパッチされたコンピュート
シェーダーのディスパッチサイズ、
vec3<u32>(group_count_x, group_count_y, group_count_z)。
|
13.3.1.1.10. position
| 名前 | position |
| ステージ | vertex |
| 型 | vec4<f32> |
| 方向 | 出力 |
| 説明 |
クリップ空間座標における、現在の頂点のクリップ位置。
出力値 (x,y,z,w) は、WebGPU の正規化デバイス座標で (x/w, y/w, z/w) に対応します。 WebGPU § 3.3 座標系およびWebGPU § 23.2.4 プリミティブクリッピングを参照してください。 w 座標が 0 の場合、動的エラー が発生します。 |
| 名前 | position |
| ステージ | fragment |
| 型 | vec4<f32> |
| 方向 | 入力 |
| 説明 |
現在のフラグメントラスタライズ点の入力位置。
rp をフラグメントのRasterizationPoint とします。 概略的には: fp.xy = rp.destination.position より詳しくは:
WebGPU § 3.3 座標系およびWebGPU § 23.2.5 ラスタライズを参照してください。 |
13.3.1.1.11. primitive_index
| 名前 | primitive_index |
| ステージ | fragment |
| 型 | u32 |
| 方向 | 入力 |
| 説明 | 現在の描画操作の開始以降、現在のインスタンスについて処理されたプリミティブ数に基づく プリミティブごとのインデックス。0 から始まり、各 点、線、または三角形プリミティブが処理されるたびに 1 ずつ増加します。描画される各インスタンス間で 0 にリセットされます。 プリミティブ再開値を使用してストリッププリミティブを再開しても、 プリミティブインデックスには影響しません。このインデックスは、プリミティブのすべてのフラグメントで一様です。 |
13.3.1.1.12. sample_index
| 名前 | sample_index |
| ステージ | fragment |
| 型 | u32 |
| 方向 | 入力 |
| 説明 |
現在のフラグメントラスタライズ点のサンプルインデックス。
値は 0 以上、
sampleCount-1 以下です。ここで sampleCount は GPU レンダーパイプラインに指定されたサンプル
count
です。
この属性が適用されている場合、フラグメントシェーダーの効果が
sample_index の値に基づいて変化するなら、フラグメントシェーダーは
サンプルごとに 1 回呼び出されます。
WebGPU § 10.3 GPURenderPipelineを参照してください。 |
13.3.1.1.13. sample_mask
| 名前 | sample_mask |
| ステージ | fragment |
| 型 | u32 |
| 方向 | 入力 |
| 説明 |
現在のフラグメントのサンプルカバレッジビットマスク。
ビットは半開区間 [0, サンプルがレンダリングされているプリミティブによって覆われている場合にのみ、ビットは 1 に設定されます。
インデックスが ビットマスクには、次の 2 つの可能な値があります:
注: 注: これは WebGPU § 23.2.10 サンプル単位シェーディングおよびWebGPU § 23.2.11 サンプル マスキングを参照してください。 |
| 名前 | sample_mask |
| ステージ | fragment |
| 型 | u32 |
| 方向 | 出力 |
| 説明 |
現在のフラグメントのサンプルカバレッジマスク制御。この変数に最後に
書き込まれた値がシェーダー出力マスクになります。書き込まれた値の
0 ビットにより、カラーアタッチメント内の対応するサンプルが
破棄されます。
WebGPU § 23.2.11 サンプルマスキングを参照してください。 |
13.3.1.1.14. vertex_index
| 名前 | vertex_index |
| ステージ | vertex |
| 型 | u32 |
| 方向 | 入力 |
| 説明 |
現在の API レベルの描画コマンド内における現在の頂点のインデックスで、
描画のインスタンス化とは無関係です。
非インデックス描画の場合、最初の頂点のインデックスは、直接指定されたか間接的に指定されたかにかかわらず、
描画の インデックス描画の場合、インデックスは
頂点のインデックスバッファーエントリーに、直接指定されたか
間接的に指定されたかにかかわらず描画の |
13.3.1.1.15. workgroup_id
| 名前 | workgroup_id |
| ステージ | compute |
| 型 | vec3<u32> |
| 方向 | 入力 |
| 説明 |
現在の呼び出しのワークグループ
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 |
| ステージ | compute |
| 型 | u32 |
| 方向 | 入力 |
| 説明 |
現在の呼び出しのワークグループインデックス、すなわち、
全体のコンピュートシェーダーグリッド内における
ワークグループの線形位置です。
同じワークグループ内のすべての呼び出しは、同じワークグループインデックスを持ちます。
注: ディスパッチされた
ワークグループ数によってこの値がu32
型の範囲を超える場合、ディスパッチは失敗します:
|
13.3.1.1.17. subgroup_invocation_id
| 名前 | subgroup_invocation_id |
| ステージ | compute または fragment |
| 型 | u32 |
| 方向 | 入力 |
| 説明 |
現在の呼び出しのサブグループ呼び出し ID。
ID は [0, subgroup_size - 1] の範囲内です。 compute シェーダーでは、ID は 0 から始まり密です。 つまり、コンピュートシェーダーが実行を開始したとき、各サブグループ内で:
注: フラグメントシェーダーでのサブグループ呼び出しのインデックス付けは 密でない場合があります。実装は より小さい番号の ID の一部をヘルパー呼び出しに割り当てる場合があります。 |
13.3.1.1.18. subgroup_size
| 名前 | subgroup_size |
| ステージ | compute または fragment |
| 型 | u32 |
| 方向 | 入力 |
| 説明 |
現在の呼び出しのサブグループのサブグループサイズ。
subgroup_size 属性を持つコンピュートシェーダーでは、この値は 指定された属性値に等しくなります。 |
13.3.1.1.19. subgroup_id
| 名前 | subgroup_id |
| ステージ | compute |
| 型 | u32 |
| 方向 | 入力 |
| 説明 |
現在の呼び出しのワークグループ内における、
現在の呼び出しのサブグループのサブグループ ID。
ID は [0, num_subgroups - 1] の範囲内です。 |
13.3.1.1.20. num_subgroups
| 名前 | num_subgroups |
| ステージ | compute |
| 型 | u32 |
| 方向 | 入力 |
| 説明 | 現在の呼び出しのワークグループ内の サブグループの数。 |
13.3.1.2. ユーザー定義の入力と出力
ユーザー定義データは、パイプラインの開始時に入力として渡したり、 パイプラインのステージ間で渡したり、パイプラインの終端から出力したりできます。
各ユーザー定義 入力データおよび ユーザー定義 出力データは、次を満たさなければなりません:
-
IO ロケーションが割り当てられていること。§ 13.3.1.3 入出力 ロケーションを参照してください。
compute シェーダーはユーザー定義の 入力または出力を持ってはなりません。
13.3.1.3. 入出力ロケーション
各入出力ロケーションには、最大 16 バイトの値を格納できます。 型のバイトサイズは、§ 14.4.1 アラインメントとサイズの SizeOf 列を使用して定義されます。 たとえば、浮動小数点値の 4 成分ベクトルは 1 つのロケーションを占有します。
IO ロケーションはlocation 属性によって指定されます。
各ユーザー定義入力および出力には、明示的に指定された IO ロケーションがなければなりません。 エントリーポイント IO 内の各構造体メンバーは、組み込み値 (§ 13.3.1.1 組み込み入力と出力を参照)であるか、ロケーションが割り当てられているかの いずれかでなければなりません。
-
members 内のいずれかのエントリーがblend_src 属性を指定する場合、 members は デュアルソースブレンディングを使用しなければなりません。これは次を意味します:
-
members は正確に
2個の エントリーを含まなければならず、 1 つは@location(0) @blend_src(0)、もう 1 つは@location(0) @blend_src(1)です。 -
すべての 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
-
補間はサンプルごとに行われます。 この属性が適用されると、fragment シェーダーは サンプルごとに 1 回呼び出されます。
- first
-
値はプリミティブの最初の頂点によって提供されます。
- either
-
値はプリミティブの最初の頂点または最後の頂点によって提供されます。 値が最初と最後のどちらの頂点から来るかは実装依存です。
スカラー型またはベクトル浮動小数点型のユーザー定義 IO について:
-
補間属性が指定されていない場合、
@interpolate(perspective, center)が指定されたものとみなされます。 -
補間属性に補間型が指定されている場合:
スカラー型またはベクトル整数型のユーザー定義vertex 出力およびfragment 入力は、常に補間型
flat を指定しなければなりません。
ステージ間インターフェイス検証は、 レンダー パイプライン内で、 各ユーザー定義fragment 入力の補間プロパティが、 同じ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. バッファーバインディングによるランタイムサイズ配列の要素数の決定
storage バッファー
変数がランタイムサイズ配列を含む場合、その配列内の要素数は
対応する resource
のサイズから決定されます:
T をstorage バッファー変数の格納型とします。 ここで T はランタイムサイズ配列型であるか、ランタイムサイズ配列 型を含みます。
bufferBinding を バッファーバインディングとして取得する(
resource) とします。EBS を、storage バッファー変数に対応するパイプラインバインディングアドレスに バインドされた bufferBinding の 実効バッファーバインディングサイズ とします。
すると NRuntime、 すなわち ランタイムサイズ配列内の要素数は、SizeOf(T) ≤ EBS を満たす最大の整数です。
より詳しくは、型 RAT のランタイムサイズ配列のNRuntime は:
truncate((EBBS − array_offset) ÷ array_stride)。ここで:
EBBS は変数に関連付けられた実効バッファーバインディングサイズ、
array_offset は、変数の格納型内におけるランタイムサイズ配列のバイトオフセットです。
格納型がランタイムサイズ配列型そのものである RAT の場合は 0 です。
それ以外の場合、格納型は構造体であり、その最後のメンバーがランタイムサイズ配列です。 この場合、array_offset は構造体内におけるそのメンバーのバイトオフセットです。
array_stride は配列型のストライド、すなわち StrideOf(RAT) です。
シェーダーは arrayLength 組み込み関数を介してNRuntime を計算できます。
NRuntime は 対応するバッファーバインディングのサイズによって決定され、そのサイズは描画 またはディスパッチコマンドごとに異なる場合があります。
WebGPU の検証規則により、1 ≤ NRuntime が保証されます。
-
weights変数はstorage バッファーです。 -
その格納型はランタイムサイズ配列型
array<f32>です。 -
配列オフセットは 0 です。
-
配列ストライドは StrideOf(array<f32>)、すなわち 4 です。
次の表は、対応する実効バッファーバインディングサイズに基づく、
weights 変数のNRuntime
の例を示します。
| 実効バッファーバインディングサイズ | weights 変数の NRuntime
| 計算 |
|---|---|---|
| 1024 | 256 | truncate( 1024 ÷ 4 ) |
| 1025 | 256 | truncate( 1025 ÷ 4 ) |
| 1026 | 256 | truncate( 1026 ÷ 4 ) |
| 1027 | 256 | truncate( 1027 ÷ 4 ) |
| 1028 | 257 | truncate( 1028 ÷ 4 ) |
-
lights変数はstorage バッファーです。 -
その格納型は
LightStorageです。 -
LightStorageのpointメンバーは、 型array<PointLight>のランタイムサイズ配列です。
struct PointLight { // align(16) size(32) position: vec3f, // offset(0) align(16) size(12) // -- 暗黙のメンバーアラインメントパディング -- // offset(12) size(4) color : vec3f, // offset(16) align(16) size(12) // -- 暗黙の構造体サイズパディング -- // offset(28) size(4) } struct LightStorage { // align(16) pointCount : u32, // offset(0) align(4) size(4) // -- 暗黙のメンバーアラインメントパディング -- // offset(4) size(12) point : array< PointLight > , // offset(16) align(16) elementsize(32) } @group ( 0 ) @binding ( 1 ) var < storage> lights : LightStorage ;
次の表は、lights 変数の point メンバーについてのNRuntime の例を示します。
| 実効バッファーバインディングサイズ | lights 変数の point メンバーの NRuntime
| 計算 |
|---|---|---|
| 1024 | 31 | truncate( ( 1024 - 16 ) ÷ 32) ) |
| 1025 | 31 | truncate( ( 1025 - 16 ) ÷ 32) ) |
| 1039 | 31 | truncate( ( 1039 - 16 ) ÷ 32) ) |
| 1040 | 32 | truncate( ( 1040 - 16 ) ÷ 32) ) |
14. メモリー
WGSL では、格納可能型の値を 後で取得するためにメモリーへ格納できます。 この節では、メモリーの構造と、メモリーへアクセスする操作のセマンティクスについて説明します。 メモリーに配置できる値の型、および メモリーアクセスの実行に使用される型については、§ 6.5 メモリービューを参照してください。
14.1. メモリー位置
メモリーは、個別のメモリー位置の集合から構成されます。 各メモリー位置のサイズは 8 ビットです。 メモリーに影響する操作は、1 つ以上のメモリー位置の集合と相互作用します。 複合値に対するメモリー操作は、 パディングのメモリー位置へアクセスしません。 したがって、操作によってアクセスされるメモリー位置の集合は連続していない場合があります。
2 つのメモリー位置の集合は、それらのメモリー位置集合の共通部分が空でない場合、 重複するといいます。
14.2. メモリーアクセスモード
メモリーアクセスは、 メモリー位置に作用する操作です。
-
読み取りアクセス はメモリー位置の内容を観測します。
-
書き込みアクセス はメモリー位置の内容を設定します。
1 つの操作で、読み取り、書き込み、または読み書きの両方を行うことができます。
特定のメモリー位置では、特定の種類のアクセスだけがサポートされる場合があり、 これはメモリーのアクセス モードとして表されます。
| アクセスモード | サポートされるアクセス |
|---|---|
| read | 読み取りアクセスをサポートしますが、書き込みはサポートしません。 |
| write | 書き込みアクセスをサポートしますが、読み取りはサポートしません。 |
| read_write | 読み取りアクセスと書き込みアクセスの両方をサポートします。 |
WGSL は列挙子 read、
write、および read_write を事前宣言します。
14.3. アドレス空間
メモリー位置はアドレス空間に分割されます。 各アドレス空間には、可変性、可視性、格納できる値、 およびそのアドレス空間で変数を使用する方法を決定する固有のプロパティがあります。 詳細については、§ 7 変数宣言と値宣言を参照してください。
特定のメモリー ビューのアクセスモードは、多くの場合コンテキストによって決定されます:
storage アドレス空間は、read および read_write アクセス モードの両方をサポートします。 その他の各アドレス空間は 1 つのアクセスモードだけをサポートします。 各アドレス空間のデフォルトアクセスモードを次の 表に示します。
| アドレス空間 | 呼び出し間での共有 | デフォルトアクセスモード | 注記 |
|---|---|---|---|
| function | 同じ呼び出しのみ | read_write | |
| private | 同じ呼び出しのみ | read_write | |
| workgroup | 同じコンピュートシェーダーのワークグループ内の呼び出し | read_write | 最外配列の要素数は、 パイプラインでオーバーライド可能な定数である場合があります。 |
| uniform | 同じシェーダーステージ内の呼び出し | read | uniform バッファー変数用 |
| storage | 同じシェーダーステージ内の呼び出し | read | storage バッファー変数用 |
| immediate | 同じシェーダーステージ内の呼び出し | read | 即時
データ変数用。 各エントリーポイントは、 最大 1 つの immediate 変数に静的にアクセスできます。 |
| handle | 同じシェーダーステージ内の呼び出し | read | サンプラー
およびテクスチャー
変数用。 |
WGSL は handle アドレス空間を除く各アドレス空間について、
列挙子を事前宣言します。
workgroup アドレス空間の変数は、 コンピュートシェーダーステージ内でのみ静的に アクセスしなければなりません。
storage
アドレス空間の変数(storage バッファー)は、
アクセスモードがread の場合に限り、頂点シェーダーステージによって静的に
アクセスできます。
格納型が
write またはread_write アクセスモードを持つストレージテクスチャー
である変数は、頂点シェーダーステージによって静的に
アクセスできません。
WebGPU createBindGroupLayout()を参照してください。
注: 各アドレス空間は異なるパフォーマンス 特性を持つ場合があります。
WGSL ソースで変数宣言またはポインター型を記述する場合:
-
その他のアドレス空間では、アクセスモードを記述してはなりません。
14.4. メモリーレイアウト
WGSL における型のレイアウトはアドレス空間に依存しません。 ただし厳密には、そのレイアウトを観測できるのはホスト共有可能な バッファーだけです。 uniform バッファー変数およびstorage バッファー変数は、 メモリー内のバイト列として編成された大量のデータを共有するために使用されます。 バッファーは 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 |
| struct S、 メンバー M1...MN を持つ | max(AlignOfMember(S,1), ... , AlignOfMember(S,N)) | roundUp(AlignOf(S),
justPastLastMember) ここで justPastLastMember = OffsetOfMember(S,N) + SizeOfMember(S,N) |
| array<E,
N> | AlignOf(E) | N × roundUp(AlignOf(E), SizeOf(E)) |
| array<E> | AlignOf(E) | NRuntime × roundUp(AlignOf(E),SizeOf(E)) ここで NRuntime は T の実行時に決定される要素数 |
| 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 番目のメンバーの型です。
最初の構造体メンバーの、構造体の先頭からのバイトオフセットは常に 0 です:
OffsetOfMember(S, 1) = 0
後続の各メンバーは、メンバー型のアラインメントを満たし、 かつ前のメンバーとの重複を避ける最小のオフセットに配置されます。 各メンバーインデックス i > 1 について:
OffsetOfMember(S, i) = roundUp(AlignOfMember(S, i ), OffsetOfMember(S, i-1) + SizeOfMember(S, i-1))
struct A { // align(8) size(24) u : f32, // offset(0) align(4) size(4) v : f32, // offset(4) align(4) size(4) w : vec2< f32> , // offset(8) align(8) size(8) x : f32// offset(16) align(4) size(4) // -- 暗黙の構造体サイズパディング -- // offset(20) size(4) } struct B { // align(16) size(160) a : vec2< f32> , // offset(0) align(8) size(8) // -- 暗黙のメンバーアラインメントパディング -- // offset(8) size(8) b : vec3< f32> , // offset(16) align(16) size(12) c : f32, // offset(28) align(4) size(4) d : f32, // offset(32) align(4) size(4) // -- 暗黙のメンバーアラインメントパディング -- // offset(36) size(4) e : A , // offset(40) align(8) size(24) f : vec3< f32> , // offset(64) align(16) size(12) // -- 暗黙のメンバーアラインメントパディング -- // offset(76) size(4) g : array< A , 3 > , // element stride 24 offset(80) align(8) size(72) h : i32// offset(152) align(4) size(4) // -- 暗黙の構造体サイズパディング -- // offset(156) size(4) } @group ( 0 ) @binding ( 0 ) var < storage, read_write> storage_buffer : B ;
struct A { // align(8) size(32) u : f32, // offset(0) align(4) size(4) v : f32, // offset(4) align(4) size(4) w : vec2< f32> , // offset(8) align(8) size(8) @size ( 16 ) x : f32// offset(16) align(4) size(16) } struct B { // align(16) size(208) a : vec2< f32> , // offset(0) align(8) size(8) // -- 暗黙のメンバーアラインメントパディング -- // offset(8) size(8) b : vec3< f32> , // offset(16) align(16) size(12) c : f32, // offset(28) align(4) size(4) d : f32, // offset(32) align(4) size(4) // -- 暗黙のメンバーアラインメントパディング -- // offset(36) size(12) @align ( 16 ) e : A , // offset(48) align(16) size(32) f : vec3< f32> , // offset(80) align(16) size(12) // -- 暗黙のメンバーアラインメントパディング -- // offset(92) size(4) g : array< A , 3 > , // element stride 32 offset(96) align(8) size(96) h : i32// offset(192) align(4) size(4) // -- 暗黙の構造体サイズパディング -- // offset(196) size(12) } @group ( 0 ) @binding ( 0 ) var < uniform> uniform_buffer : B ;
14.4.3. 配列レイアウトの例
// 次の配列: // - アラインメントは 4 = AlignOf(f32) // - 要素ストライドは 4 = roundUp(AlignOf(f32),SizeOf(f32)) = roundUp(4,4) // - サイズは 32 = stride * number_of_elements = 4 * 8 var small_stride : array< f32, 8 > ; // 次の配列: // - アラインメントは 16 = AlignOf(vec3<f32>) = 16 // - 要素ストライドは 16 = roundUp(AlignOf(vec3<f32>), SizeOf(vec3<f32>)) // = roundUp(16,12) // - サイズは 128 = stride * number_of_elements = 16 * 8 var bigger_stride : array< vec3< f32> , 8 > ;
// 次の配列: // - アラインメントは 4 = AlignOf(f32) // - 要素ストライドは 4 = roundUp(AlignOf(f32),SizeOf(f32)) = 4 // B が描画またはディスパッチコマンドのバインディングの // 実効バッファーバインディングサイズの場合、要素数は: // N_runtime = floor(B / element stride) = floor(B / 4) @group ( 0 ) @binding ( 0 ) var < storage> weights : array< f32> ; // 次の配列: // - アラインメントは 16 = AlignOf(vec3<f32>) = 16 // - 要素ストライドは 16 = roundUp(AlignOf(vec3<f32>), SizeOf(vec3<f32>)) // = roundUp(16,12) // B が描画またはディスパッチコマンドのバインディングの // 実効バッファーバインディングサイズの場合、要素数は: // N_runtime = floor(B / element stride) = floor(B / 16) var < storage> directions : array< vec3< f32>> ;
14.4.4. 値の内部レイアウト
この節では、値全体の配置が仮定されている場合に、 ホスト共有可能値の内部がバッファーのバイト位置にどのように配置されるかを説明します。 これらのレイアウトは値の型と、 構造体メンバー上のalign およびsize 属性に依存します。 これらの規則は、以下で説明する非不透明型に適用されます。 buffer 型の値には内部 構造がなく、これらの規則による制約を受けません。
値が配置されるバッファーバイトオフセットは、型のアラインメント要件を満たさなければなりません: 型 T の値がバッファーオフセット k に 配置される場合、ある 0 以上の整数 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 アドレス空間と同じ 制約を持ちます。
変数によって直接または間接的に参照されるすべての構造体型および配列型は、 その変数のアドレス空間の制約に従わなければなりません。 アドレス空間制約への違反はシェーダー作成エラーになります。
この節では、RequiredAlignOf(S, C) を、 ホスト共有可能型または固定フットプリント型 S の値を アドレス空間 C で使用するときのバイトオフセットのアラインメント要件として定義します。
| ホスト共有可能型または固定フットプリント型 S、 S が C に現れることができると仮定 | RequiredAlignOf(S, C), uniform_buffer_standard_layout がサポートされているか、 C がuniform ではない | RequiredAlignOf(S, C), uniform_buffer_standard_layout がサポートされておらず、 C がuniform |
|---|---|---|
| bool、i32、u32、f32、 またはf16 | AlignOf(S) | AlignOf(S) |
| atomic<T> | AlignOf(S) | AlignOf(S) |
| vecN<T> | AlignOf(S) | AlignOf(S) |
| matCxR<T> | AlignOf(S) | AlignOf(S) |
| array<T, N> | AlignOf(S) | roundUp(16, AlignOf(S)) |
| array<T> | AlignOf(S) C がuniform の場合、 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 は 0 以上の整数で、構造体 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)) でなければなりません。
注: 次の例は、uniform バッファーのレイアウト要件を 満たすために、構造体メンバー上で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 > // stride 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 > // stride 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の場合にのみ書き込みを行います。
-
アトミック読み取り・変更・書き込み組み込み関数は、 読み取り アクセスと書き込み アクセスの両方である 1 つのメモリー操作を実行します。
読み取りアクセスと書き込みアクセスは、その他の状況では発生しません。 読み取りアクセスと書き込みアクセスは、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 が真であるということと同じです。
逆に、何かの一様性を保証できないこと (例: スレッド ID を保持する変数)を表現するため、その対応するノードから MayBeNonUniform へのエッジを追加します。 これを理解する 1 つの方法は、MayBeNonUniform が命題 False に対応すると考えることであり、その場合 X -> MayBeNonUniform は、 X が偽であるということと同じです。
この解釈の帰結として、RequiredToBeUniform.error から到達可能なすべてのノードは、 プログラムが有効であるために一様であることを要求される何かに対応し、 MayBeNonUniform に 到達可能なすべてのノードは、一様性を保証できない何かに対応します。 したがって、RequiredToBeUniform.error からMayBeNonUniform へのパスが 1 つでもある場合、 一様性違反となり、一様性違反がトリガーされます。
ノード 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 に初期化します。
-
-
重大度 S を {error、warning、info} の順にそれぞれ処理し、次を実行します:
-
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 に p 用の変数を使用する 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 の すべてのメモリー位置に対するメモリービューです。
完全 参照でない参照は、部分参照です。 したがって、部分参照は次のいずれかです:
メンバーを 1 つ持つ構造体型と、その型を格納する変数を考えます:
struct S { member : i32; } fn foo () { var v : S ; }
この場合、v は完全参照で、v.member は部分参照です。
それらのメモリービューは同じメモリー
位置を覆いますが、v の格納型は S であり、
v.s の格納型は i32 です。
要素を 1 つ持つ配列でも同様の状況が発生します:
fn foo () { var arr : array< i32, 1 > ; }
この場合、arr は完全参照で、arr[0] は部分参照です。
それらのメモリービューは同じメモリー
位置を覆いますが、arr の格納型は array<i32,1> であり、
arr[0] の格納型は i32 です。
解析を簡単にするため、あらゆる種類の部分参照を介する代入は、 関連付けられた起点変数内の すべてのメモリー位置を変更しないものとして扱われます。 これにより解析は保守的になり、厳密には必要でないより多くのプログラムについて一様性違反がトリガーされる可能性があります。
完全スウィズルビューは、 次を満たすスウィズルビュー 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 の静的解析では、文の動作が {Next} である場合、 if、switch、およびloop 文の終端で 一様制御フローへ戻ると保守的に仮定します。 これは前の表で、結果の制御フローノードが 入力制御フローノードと同じであるものとしてモデル化されています。
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 です。
-
それ以外の場合、呼び出しサイトタグはCallSiteRequiredToBeUniform.S であり、潜在トリガー集合は derivative_uniformity 要素からなります。
-
-
そのような DF が存在しない場合、 呼び出しサイトタグはCallSiteRequiredToBeUniform.error であり、潜在トリガー集合は derivative_uniformity 要素からなります。
-
-
それ以外の場合は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 です。
-
それ以外の場合、呼び出しサイトタグはCallSiteRequiredToBeUniform.S であり、潜在トリガー集合は subgroup_uniformity 要素からなります。
-
-
そのような DF が存在しない場合、 呼び出しサイトタグはCallSiteRequiredToBeUniform.error であり、潜在トリガー集合は subgroup_uniformity 要素からなります。
-
-
それ以外の場合はCallSiteNoRestriction。
-
-
さらに、subgroupShuffleUp またはsubgroupShuffleDown の呼び出しの場合、 パラメーター
deltaのパラメータータグは次のとおりです:-
subgroup_uniformity が サポートされていないか、一様性スコープが subgroup の場合:
-
DF が存在する場合、S を DF の新しい重大度 パラメーターとします。
-
S が重大度off の場合、 パラメータータグはNoRestriction です。
-
それ以外の場合、パラメータータグはParameterRequiredToBeUniform.S であり、潜在トリガー集合は subgroup_uniformity 要素からなります。
-
-
そのような DF が存在しない場合、 パラメータータグはParameterRequiredToBeUniform.error であり、潜在トリガー集合は subgroup_uniformity 要素からなります。
-
-
それ以外の場合はNoRestriction。
-
-
さらに、subgroupShuffleXor の呼び出しの場合、 パラメーター
maskのパラメータータグは次のとおりです:-
subgroup_uniformity が サポートされていないか、一様性スコープが subgroup の場合:
-
DF が存在する場合、S を DF の新しい重大度 パラメーターとします。
-
S が重大度off の場合、 パラメータータグはNoRestriction です。
-
それ以外の場合、パラメータータグはParameterRequiredToBeUniform.S であり、潜在トリガー集合は subgroup_uniformity 要素からなります。
-
-
そのような DF が存在しない場合、 パラメータータグはParameterRequiredToBeUniform.error であり、潜在トリガー集合は subgroup_uniformity 要素からなります。
-
-
それ以外の場合は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 文の条件が一様値
(たとえば各呼び出しがuniform
バッファーから同じ値を読み取る場合)であれば、
プログラムも有効でした。
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は、その呼び出しに対応するワークグループグリッド点の 座標 3 つ組 (i,j,k) です。
呼び出しがローカル呼び出し IDを持つ場合、その ローカル呼び出し インデックスは次のとおりです:
i + (j × workgroup_size_x) + (k × workgroup_size_x × workgroup_size_y)
ワークグループに W 個の呼び出しがある場合、 そのワークグループの各呼び出し I は、一意のローカル呼び出しインデックス L(I) を持ち、 0 ≤ L(I) < W を満たし、 その範囲全体が網羅されることに注意してください。
コンピュートシェーダーは、WebGPU 実装が キューからディスパッチコマンドを取り出し、GPU 上で指定された処理を開始すると実行を開始します。 ディスパッチコマンドはディスパッチサイズを指定します。 これは整数の 3 つ組 (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は、その呼び出しに対応するコンピュートシェーダーグリッド点の 座標 3 つ組です。
呼び出しはワークグループに編成され、各呼び出しの グローバル呼び出し ID (CSi, CSj, CSk) は、 ワークグループ IDによって識別される 1 つのワークグループへ対応付けられます:
( ⌊ CSi ÷ workgroup_size_x ⌋, ⌊ CSj ÷ workgroup_size_y ⌋, ⌊ CSk ÷ workgroup_size_z ⌋)
さらに、そのワークグループ内の 1 つの呼び出しが、ローカル呼び出し IDによって識別されます:
( CSi mod workgroup_size_x , CSj mod workgroup_size_y , CSk mod workgroup_size_z ).
注: ワークグループ ID の範囲は (0,0,0) から (group_count_x - 1, group_count_y - 1, group_count_z - 1) です。
linear_indexing 機能がサポートされている場合、 ワークグループがワークグループ ID (WGi, WGj, WGk) を持つとき、その ワークグループインデックスは:
WGi + ( WGj × group_count_x ) + ( WGk × group_count_x × group_count_y )
linear_indexing 機能がサポートされている場合、 呼び出しがグローバル呼び出し ID (CSi, CSj, CSk) を持つとき、その グローバル呼び出し インデックスは:
CSi + ( CSj × workgroup_size_x × group_count_x ) + ( CSk × workgroup_size_x × group_count_x × workgroup_size_y × group_count_y )
WebGPU は次について何も保証しません:
-
異なるワークグループの呼び出しが同時に実行されるかどうか。 つまり、一度に複数のワークグループが実行されると仮定することはできません。
-
あるワークグループの呼び出しが実行を開始した後、 他のワークグループが実行を阻止されるかどうか。 つまり、一度に 1 つのワークグループだけが実行されると仮定することもできません。 ワークグループの実行中、実装は他のワークグループや、 キューに入っているがブロックされていない他の処理を同時に実行することもできます。
-
特定の 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. サブグループ
サブグループは、 compute またはfragment シェーダーステージのエントリーポイントを同時に 実行し、データを効率的に共有して結果を集合的に計算できる呼び出しの集合です。 compute または fragment シェーダーの各呼び出しは、正確に 1 つのサブグループに属します。 compute シェーダーでは、各サブグループは特定のワークグループの部分集合です。 fragment シェーダーでは、サブグループに複数の描画コマンドからの呼び出しが含まれる場合があります。 各クワッドは単一の サブグループ内に含まれます。
サブグループサイズは、 サブグループ内の呼び出しの最大数です。 シェーダー内では、この値にはsubgroup_size 組み込み値を介してアクセスできます。 サブグループサイズは、ディスパッチコマンド内、したがってワークグループ内では一様 値ですが、描画コマンド内では一様値でない場合があります。 すべてのサブグループサイズは [4, 128] の範囲内の 2 のべき乗であり、特定のデバイス向けに コンパイルされたシェーダーの値は、WebGPU § 4.3 GPUAdapter の [subgroupMinSize, subgroupMaxSize] の範囲内になります。 実際のサイズは、シェーダー、デバイスのプロパティ、およびデバイスコンパイラーに依存します。 各デバイスは、可能なサブグループサイズ範囲の部分集合(単一の値の場合もあります)をサポートします。 デバイスコンパイラーは、さまざまなヒューリスティックを用いて、サポートされるサイズから 1 つを選択します。 各サブグループに含まれる呼び出し数は、報告されたサブグループサイズより少ない場合があります (たとえば、起動された呼び出し数がサブグループサイズより少ない場合)。
呼び出しのサブグループ呼び出し
IDは、サブグループ内の一意の ID です。
この ID にはsubgroup_invocation_id
組み込み値を介してアクセスでき、範囲 [0, subgroup_size - 1] 内にあります。
subgroup_id 機能がサポートされている場合、compute シェーダー内のサブグループ IDは、ワークグループ内の サブグループに対する一意の ID です。 この ID にはsubgroup_id 組み込み値を介してアクセスでき、 範囲 [0, num_subgroups - 1] 内にあります。
サブグループ値(すなわち
subgroup_invocation_id および subgroup_id)とlocal_invocation_index の間には、定義された関係はありません。
移植不能なコードを避けるため、シェーダー作成者は、これら 2 つの値の間に特定の
対応付けがあると仮定するべきではありません。
同じサブグループ内の呼び出しが異なる制御フローパスを実行する場合、 サブグループの実行は分岐したといいます。 これは非一様制御フローの特殊な場合です。 分岐はサブグループ操作のセマンティクスに影響します。 サブグループ操作を同時に実行するサブグループ内の呼び出しは、その操作についてアクティブです。 サブグループ内のその他の呼び出しは、その操作について非アクティブ です。 サブグループサイズがサブグループ内の呼び出し数を超える場合、 追加の仮想的な呼び出しは非アクティブとみなされます。 ヘルパー呼び出しは、 操作内でアクティブまたは非アクティブになる場合があります。 つまり、一部のデバイスではヘルパー呼び出しがサブグループ操作に参加する場合がありますが、 他のデバイスでは参加しない場合があります。
注: 非一様制御フローで 動作する場合、基盤となるデバイス間にはかなりの移植性の違いがあり、 デバイスコンパイラーはそのようなコードを積極的に最適化することがよくあります。 その結果、サブグループにはシェーダー作成者が予想したものとは異なるアクティブ 呼び出しの集合が含まれる場合があります。
15.6. 集合操作
15.6.1. バリア
バリアは、プログラム内のメモリー操作を順序付ける同期組み込み関数です。 制御バリアは、 同じワークグループ内のすべての呼び出しによって、 同時に実行されたかのように実行されます。 したがって、制御バリアはcompute シェーダー内の一様制御フローでのみ実行しなければなりません。
15.6.2. 微分
偏微分は、 軸に沿った値の変化率です。 同じクワッド内のフラグメントシェーダー呼び出しは協調して、 近似的な偏微分を計算します。
微分を計算する組み込み関数は次のとおりです:
フラグメント座標の偏微分は、次の組み込み関数の動作の一部として 暗黙的に計算されます:
これらでは、微分はサンプリングするテクセルのミップレベルを決定するのに役立ち、
textureSampleCompare の場合は、サンプリングして参照値と比較するテクセルの
ミップレベルを決定するのに役立ちます。
呼び出しで指定された値の偏微分は、 § 17.6 微分組み込み 関数で説明される組み込み関数によって計算されます:
-
dpdx、dpdxCoarse、およびdpdxFine は x 軸に沿った偏微分を計算します。
-
dpdy、dpdyCoarse、およびdpdyFine は y 軸に沿った偏微分を計算します。
-
fwidth、fwidthCoarse、およびfwidthFine は、 関連する x および y の偏微分に対するマンハッタン距離を計算します。
隣接する呼び出しが協調して微分を計算するため、これらの 関数はフラグメントシェーダー内の一様制御フローでのみ呼び出すべきです。 これらの関数の各呼び出しについて、一様性解析が、 呼び出しが一様制御フローで行われることを証明できない場合、 derivative_uniformity 診断がトリガーされます。
これらの関数の 1 つが非一様制御フローで呼び出された場合、結果は不定 値です。
注: 微分は暗黙的なクワッド操作の一種です。 その使用に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 関数は、 通常の乗算(丸めステップを含む)と加算(さらにもう 1 回の丸めステップ)へ展開される場合がありますが、 IEEE-754 の
fusedMultiplyAdd演算では最終の丸めステップだけが 行われることを要求します。
15.7.3. 浮動小数点の丸めとオーバーフロー
オーバーフローする計算は、無限大または最も近い有限値へ丸められる場合があります。 結果は、オーバーフローした中間結果値の大きさと、 評価がシェーダーモジュール作成中、パイプライン作成中、またはシェーダー 実行中のいずれで発生するかによって異なります。
浮動小数点型 T について、MAX(T) を T の最大の正の有限値、 2EMAX(T) を T で表現可能な最大の 2 のべき乗として定義します。 特に、EMAX(f32) = 127、EMAX(f16) = 15 です。
X を、浮動小数点計算から得られる無限精度の中間結果とします。 式の最終値は、次のように中間結果値 X' と X'' を介して 2 段階で決定されます:
X から、丸めによって T の X' を計算します:
-
X が 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 - y で x=1.0 かつ y=1.17e-38
(最小の正の正規単精度浮動小数点数)の場合です。
これらの数の指数は 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)
| (x[i] * y[j] - x[j] * y[i]) から継承。
ここで i ≠ j
| |
degrees(x)
| x * 57.295779513082322865 から継承
| |
determinant(m:mat2x2<T>)determinant(m:mat3x3<T>)determinant(m:mat4x4<T>)
|
無限 ULP。
注:WebGPU 実装は、実用上有用な
determinant 関数を提供するべきです。
理想的な数学では、行列式は加算、減算、乗算演算で計算されます。 しかし、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 型と同一であると仮定します。
f32 値の 1 ULP は、IEEE-754 binary64 値の 1 ULP より 229 倍大きくなります。 これは、binary64 形式の仮数が f32 型の仮数より 29 ビット長いためです。
たとえば、演算の真の結果値が 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 つのオペランドが反対の符号の無限大で-md>
浮動小数点加算は、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 はスカラー
|
| 説明 | e を両方の成分とする 2 成分ベクトルを構築します。
|
| オーバーロード |
|
| パラメーター化 | T は具象スカラーS はスカラー
|
| 説明 |
e.x と e.y を成分とする 2 成分ベクトルの成分ごとの構築です。
|
| オーバーロード |
|
| パラメーター化 | T はスカラー
|
| 説明 | e1 と e2 を成分とする 2 成分ベクトルの成分ごとの構築です。
|
| オーバーロード |
|
| パラメーター化 | T は AbstractInt
|
| 説明 | 値 vec2(0,0) を返します。
|
17.1.2.18. vec3
| オーバーロード |
|
| パラメーター化 | T は具象スカラーS はスカラー
|
| 説明 | e をすべての成分とする 3 成分ベクトルを構築します。
|
| オーバーロード |
|
| パラメーター化 | T は具象スカラーS はスカラー
|
| 説明 |
e.x、e.y、および
e.z を成分とする 3 成分ベクトルの成分ごとの構築です。
|
| オーバーロード |
|
| パラメーター化 | T はスカラー
|
| 説明 | e1、e2、および e3 を成分とする
3 成分ベクトルの成分ごとの構築です。
|
| オーバーロード |
|
| パラメーター化 | T はスカラー
|
| 説明 | v1.x、v1.y、および
e1 を成分とする 3 成分ベクトルの成分ごとの構築です。
|
| オーバーロード |
|
| パラメーター化 | T はスカラー
|
| 説明 | e1、v1.x、および
v1.y を成分とする 3 成分ベクトルの成分ごとの構築です。
|
| オーバーロード |
|
| パラメーター化 | T は AbstractInt
|
| 説明 | 値 vec3(0,0,0) を返します。
|
17.1.2.19. vec4
| オーバーロード |
|
| パラメーター化 | T は具象スカラーS はスカラー
|
| 説明 | e をすべての成分とする 4 成分ベクトルを構築します。
|
| オーバーロード |
|
| パラメーター化 | T は具象スカラーS はスカラー
|
| 説明 |
e.x、e.y、e.z、
および e.w を成分とする 4 成分ベクトルの成分ごとの構築です。
|
| オーバーロード |
|
| パラメーター化 | T はスカラー
|
| 説明 | e1、e2、e3、および
e4 を成分とする 4 成分ベクトルの成分ごとの構築です。
|
| オーバーロード |
|
| パラメーター化 | T はスカラー
|
| 説明 | e1、v1.x、v1.y、
および e2 を成分とする 4 成分ベクトルの成分ごとの構築です。
|
| オーバーロード |
|
| パラメーター化 | T はスカラー
|
| 説明 | e1、e2、v1.x、
および v1.y を成分とする 4 成分ベクトルの成分ごとの構築です。
|
| オーバーロード |
|
| パラメーター化 | T はスカラー
|
| 説明 | v1.x、v1.y、
v2.x、および v2.y を成分とする 4 成分ベクトルの成分ごとの構築です。
|
| オーバーロード |
|
| パラメーター化 | T はスカラー
|
| 説明 | v1.x、v1.y、e1、
および e2 を成分とする 4 成分ベクトルの成分ごとの構築です。
|
| オーバーロード |
|
| パラメーター化 | T はスカラー
|
| 説明 | v1.x、v1.y、
v1.z、および e1 を成分とする 4 成分ベクトルの成分ごとの構築です。
|
| オーバーロード |
|
| パラメーター化 | T はスカラー
|
| 説明 | e1、v1.x、v1.y、
および v1.z を成分とする 4 成分ベクトルの成分ごとの構築です。
|
| オーバーロード |
|
| パラメーター化 | 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> |
| 説明 |
e の逆余弦(cos-1)の主値をラジアンで返します。すなわち、 cos(x) = e となる
0 ≤ x ≤ π の x を近似します。
|
| スカラー定義域 | 区間 [−1, 1] |
17.5.3. acosh
| オーバーロード |
|
| パラメーター化 | S は AbstractFloat、f32、または f16 T は S または vecN<S> |
| 説明 |
x の逆双曲線余弦(cosh-1)を双曲角として返します。すなわち、 cosh(a) = x となる
0 ≤ a ≤ +∞ の a を近似します。
|
| スカラー定義域 | 区間 [1, +∞] |
17.5.4. asin
| オーバーロード |
|
| パラメーター化 | S は AbstractFloat、f32、または f16 T は S または vecN<S> |
| 説明 |
e の逆正弦(sin-1)の主値をラジアンで返します。すなわち、 sin(x) = e となる
-π/2 ≤ x ≤ π/2 の x を近似します。
|
| スカラー定義域 | 区間 [−1, 1] |
17.5.5. asinh
| オーバーロード |
|
| パラメーター化 | S は AbstractFloat、f32、または f16 T は S または vecN<S> |
| 説明 |
y の逆双曲線正弦(sinh-1)を双曲角として返します。すなわち、 sinh(y) =
a となる a を近似します。
|
17.5.6. atan
| オーバーロード |
|
| パラメーター化 | S は AbstractFloat、f32、または f16 T は S または vecN<S> |
| 説明 |
e の逆正接(tan-1)の主値をラジアンで返します。すなわち、 tan(x) = e となる
− π/2 ≤ x ≤ π/2 の x を近似します。
|
17.5.7. atanh
| オーバーロード |
|
| パラメーター化 | S は AbstractFloat、f32、または f16 T は S または vecN<S> |
| 説明 |
t の逆双曲線正接(tanh-1)を双曲角として返します。すなわち、 tanh(a) =
t となる a を近似します。
|
| スカラー定義域 | 区間 [−1, 1] |
17.5.8. atan2
| オーバーロード |
|
| パラメーター化 | S は AbstractFloat、f32、または f16 T は S または vecN<S> |
| 説明 |
正接が y÷x である区間 [-π, π] 内の角度をラジアンで返します。
結果によって選択される象限は、
注: 結果の誤差には上限がありません:
|
17.5.9. ceil
| オーバーロード |
|
| パラメーター化 | S は AbstractFloat、f32、または f16 T は S または vecN<S> |
| 説明 | e の天井値を返します。
T がベクトルの場合は成分ごとです。
|
17.5.10. clamp
| オーバーロード |
|
| パラメーター化 | S は AbstractInt、AbstractFloat、i32、u32、f32、または f16 T は S、または vecN<S> |
| 説明 |
e の値を範囲内に制限します。
|
17.5.11. cos
| オーバーロード |
|
| パラメーター化 | S は AbstractFloat、f32、または f16 T は S または vecN<S> |
| 説明 | ラジアン単位の e の余弦を返します。
T がベクトルの場合は成分ごとです。
|
| スカラー定義域 | 区間 (−∞, +∞) |
17.5.12. cosh
| オーバーロード |
|
| パラメーター化 | S は AbstractFloat、f32、または f16 T は S または vecN<S> |
| 説明 |
双曲角である
a の双曲線余弦を返します。
純粋な数学関数 (ea +
e−a)÷2 を近似しますが、
必ずしもその方法で計算されるわけではありません。
|
17.5.13.
countLeadingZeros
| オーバーロード |
|
| パラメーター化 | T は i32、u32、vecN<i32>、または vecN<u32>
|
| 説明 | T がスカラー型の場合、e の最上位ビットから始まる
連続した 0 ビットの数。T がベクトルの場合は成分ごとです。一部の言語では "clz" とも呼ばれます。 |
17.5.14.
countOneBits
| オーバーロード |
|
| パラメーター化 | T は i32、u32、vecN<i32>、または vecN<u32>
|
| 説明 | e の表現内の 1 ビットの数。"population count" とも呼ばれます。 T がベクトルの場合は成分ごとです。
|
17.5.15.
countTrailingZeros
| オーバーロード |
|
| パラメーター化 | T は i32、u32、vecN<i32>、または vecN<u32>
|
| 説明 | T がスカラー型の場合、e の最下位ビットから始まる
連続した 0 ビットの数。T がベクトルの場合は成分ごとです。一部の言語では "ctz" とも呼ばれます。 |
17.5.16. cross
| オーバーロード |
|
| パラメーター化 | T は AbstractFloat、f32、または f16
|
| 説明 | e1 と e2 の外積を返します。
|
| 定義域 |
可能な実装によって与えられる線形項から暗黙的に導かれます:
|
17.5.17. degrees
| オーバーロード |
|
| パラメーター化 | S は AbstractFloat、f32、または f16 T は S または vecN<S> |
| 説明 | ラジアンを度に変換し、e1 × 180 ÷ π を近似します。
T がベクトルの場合は成分ごとです
|
17.5.18.
determinant
| オーバーロード |
|
| パラメーター化 | T は AbstractFloat、f32、または f16
|
| 説明 | e の行列式を返します。
|
| 定義域 | 行列式の標準的な数学的定義における線形項から暗黙的に導かれます。 |
17.5.19. distance
| オーバーロード |
|
| パラメーター化 | S は AbstractFloat、f32、または f16 T は S または vecN<S> |
| 説明 |
e1 と e2 の間の距離を返します(たとえば
length(e1 - e2))。
定義域は、
減算 e1−e2 が有効なすべてのベクトル
(e1,e2) です。
すなわち、ある成分 |
17.5.20. dot
| オーバーロード |
|
| パラメーター化 | T は AbstractInt、AbstractFloat、i32、u32、f32、または f16
|
| 説明 | e1 と e2 のドット積を返します。
|
| 定義域 | 項 e1[i] × e2[i] の総和の線形項から暗黙的に導かれます。 |
17.5.21.
dot4U8Packed
| オーバーロード |
|
| 説明 | e1 と e2 は、4 つの 8 ビット符号なし整数
成分を持つベクトルとして解釈されます。
これら 2 つのベクトルの符号なし整数ドット積を返します。
|
17.5.22.
dot4I8Packed
| オーバーロード |
|
| 説明 | e1 と e2 は、4 つの 8 ビット符号付き整数
成分を持つベクトルとして解釈されます。
これら 2 つのベクトルの符号付き整数ドット積を返します。各成分は乗算を行う前に
i32 へ符号拡張され、その後、加算演算は WGSL i32 で行われます(結果は数学的に
-65024 から 65536 の範囲内であることが保証され、この範囲は
i32 で表現可能な数の範囲内にあるため、加算はオーバーフローしません)。
|
17.5.23. exp
| オーバーロード |
|
| パラメーター化 | S は AbstractFloat、f32、または f16 T は S または vecN<S> |
| 説明 | e1 の自然指数関数(たとえば
ee1)を返します。
T がベクトルの場合は成分ごとです。
|
17.5.24. exp2
| オーバーロード |
|
| パラメーター化 | S は AbstractFloat、f32、または f16 T は S または vecN<S> |
| 説明 | 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>T がベクトルである場合に限り I もベクトルですI も抽象であり、その逆も成り立つ場合に限り、
T は抽象になれます
注: いずれかのパラメーターが具象の場合、 他方のパラメーターは (該当する場合)自動変換によって 具象 型となり、結果も 具象 型になります。 |
| 説明 |
次を除き、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 の双曲線正弦を返します。
純粋な数学関数
(ea − e−a)÷2
を近似しますが、必ずしもその方法で計算されるわけではありません。
|
17.5.57.
smoothstep
| オーバーロード |
|
| パラメーター化 | S は AbstractFloat、f32、または f16 T は S または vecN<S> |
| 説明 |
0 と 1 の間の滑らかなエルミート補間を返します。
T がベクトルの場合は成分ごと
です。
スカラー 定性的には:
|
17.5.58. sqrt
| オーバーロード |
|
| パラメーター化 | S は AbstractFloat、f32、または f16 T は S または vecN<S> |
| 説明 | e の平方根を返します。
T がベクトルの場合は成分ごと
です。
|
| スカラー定義域 | 区間 [0, +∞] |
17.5.59. step
| オーバーロード |
|
| パラメーター化 | S は AbstractFloat、f32、または f16 T は S または vecN<S> |
| 説明 | edge ≤ x の場合は 1.0、それ以外の場合は 0.0 を返します。
T がベクトルの場合は成分ごと
です。
|
17.5.60. tan
| オーバーロード |
|
| パラメーター化 | S は AbstractFloat、f32、または f16 T は S または vecN<S> |
| 説明 | ラジアン単位の e の正接を返します。
T がベクトルの場合は成分ごと
です。
|
| スカラー定義域 | 区間 (−∞, +∞) |
17.5.61. tanh
| オーバーロード |
|
| パラメーター化 | S は AbstractFloat、f32、または f16 T は S または vecN<S> |
| 説明 |
双曲角である
a の双曲線正接を返します。
純粋な数学関数
(ea − e−a) ÷ (ea +
e−a)
を近似しますが、必ずしもその方法で計算されるわけではありません。
|
17.5.62.
transpose
| オーバーロード |
|
| パラメーター化 | T は AbstractFloat、f32、または f16
|
| 説明 | e の転置を返します。
|
17.5.63. trunc
| オーバーロード |
|
| パラメーター化 | S は AbstractFloat、f32、または f16 T は S または vecN<S> |
| 説明 | truncate(e)、すなわち絶対値が
e の絶対値以下である最も近い整数を返します。
T がベクトルの場合は成分ごと
です。
|
17.6. 微分組み込み関数
§ 15.6.2 微分を参照してください。
これらの関数の呼び出しは:
-
一様性解析が 呼び出しが一様制御フロー内にあることを証明できない場合、derivative_uniformity 診断をトリガーします。
17.6.1. dpdx
| オーバーロード |
|
| パラメーター化 | T は f32 または vecN<f32>
|
| 説明 |
ウィンドウ x 座標に関する e の偏微分。
結果は dpdxFine(e) または dpdxCoarse(e) のいずれかと同じです。
|
17.6.2. dpdxCoarse
| オーバーロード |
|
| パラメーター化 | T は f32 または vecN<f32>
|
| 説明 |
局所差分を使用して、ウィンドウ x 座標に関する e の偏微分を返します。
これにより、dpdxFine(e) より一意の位置が少なくなる場合があります。
|
17.6.3. dpdxFine
| オーバーロード |
|
| パラメーター化 | T は f32 または vecN<f32>
|
| 説明 |
ウィンドウ x 座標に関する e の偏微分を返します。
|
17.6.4. dpdy
| オーバーロード |
|
| パラメーター化 | T は f32 または vecN<f32>
|
| 説明 |
ウィンドウ y 座標に関する e の偏微分。
結果は dpdyFine(e) または dpdyCoarse(e) のいずれかと同じです。
|
17.6.5. dpdyCoarse
| オーバーロード |
|
| パラメーター化 | T は f32 または vecN<f32>
|
| 説明 |
局所差分を使用して、ウィンドウ y 座標に関する e の偏微分を返します。
これにより、dpdyFine(e) より一意の位置が少なくなる場合があります。
|
17.6.6. dpdyFine
| オーバーロード |
|
| パラメーター化 | T は f32 または vecN<f32>
|
| 説明 |
ウィンドウ y 座標に関する e の偏微分を返します。
|
17.6.7. fwidth
| オーバーロード |
|
| パラメーター化 | T は f32 または vecN<f32>
|
| 説明 |
abs(dpdx(e)) + abs(dpdy(e)) を返します。
|
17.6.8.
fwidthCoarse
| オーバーロード |
|
| パラメーター化 | T は f32 または vecN<f32>
|
| 説明 |
abs(dpdxCoarse(e)) + abs(dpdyCoarse(e)) を返します。
|
17.6.9. fwidthFine
| オーバーロード |
|
| パラメーター化 | T は f32 または vecN<f32>
|
| 説明 |
abs(dpdxFine(e)) + abs(dpdyFine(e)) を返します。
|
17.7. テクスチャー組み込み関数
パラメーター値は、それぞれのテクスチャー型に対して有効でなければなりません。
17.7.1. textureDimensions
テクスチャー、またはテクスチャーのミップレベルのテクセル単位の次元を返します。
| パラメーター化 | オーバーロード |
|---|---|
| ST はi32、u32、またはf32 F はテクセル フォーマット A はアクセス モード T は texture_1d<ST> または texture_storage_1d<F,A>
|
|
|
ST はi32、u32、またはf32 T は texture_1d<ST>
|
|
| ST はi32、u32、またはf32 F はテクセル フォーマット A はアクセス モード T は texture_2d<ST>、texture_2d_array<ST>、
texture_cube<ST>、
texture_cube_array<ST>、texture_multisampled_2d<ST>、
texture_depth_2d、texture_depth_2d_array、
texture_depth_cube、
texture_depth_cube_array、texture_depth_multisampled_2d、
texture_storage_2d<F,A>、texture_storage_2d_array<F,A>、
または texture_external
|
|
|
ST はi32、u32、またはf32 T は texture_2d<ST>、texture_2d_array<ST>、
texture_cube<ST>、
texture_cube_array<ST>、texture_depth_2d、
texture_depth_2d_array、
texture_depth_cube、または texture_depth_cube_array
|
|
| ST はi32、u32、またはf32 F はテクセル フォーマット A はアクセス モード T は texture_3d<ST> または texture_storage_3d<F,A>
|
|
|
ST はi32、u32、またはf32 T は texture_3d<ST>
|
|
パラメーター:
t
| サンプリング、 マルチサンプリング、深度、 ストレージ、または外部 テクスチャー。 |
level
|
ミップレベル。レベル
0 はテクスチャーのフルサイズ版を含みます。 省略した場合、レベル 0 の次元が返されます。 |
戻り値:
テクスチャーの座標次元。
すなわち、結果は論理テクセルアドレスの座標に対する整数境界を提供し、 ミップレベル数、配列サイズ、およびサンプル数は除外されます。
キューブに基づくテクスチャーでは、結果はキューブの各面の次元です。 キューブの面は正方形であるため、結果の x 成分と y 成分は等しくなります。
level が範囲 [0, textureNumLevels(t)) 外の場合、戻り値の型の不定
値
が返される場合があります。
17.7.2. textureGather
テクスチャーギャザー 操作は 2D、2D 配列、キューブ、またはキューブ配列テクスチャーから読み取り、 次のように 4 成分ベクトルを計算します:
-
線形フィルタリングを使用するサンプリング操作で使用される 4 つのテクセルを、 ミップレベル 0 から見つけます:
-
指定された座標、配列インデックス(存在する場合)、およびオフセット(存在する場合)を使用します。
-
テクセルは、テクスチャー空間座標 (u,v) で見ると隣接し、正方形を形成します。
-
テクスチャー端、キューブ面の端、またはキューブの角で選択されたテクセルは、 通常のテクスチャーサンプリングと同様に処理されます。
-
-
各テクセルについて、1 つのチャンネルを読み取り、それをスカラー値へ変換します。
-
深度以外のテクスチャーでは、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 式は必ずconst 式(たとえば
1)でなければなりません。その値は 0 以上 3 以下でなければなりません。 この範囲外の値はシェーダー作成 エラーになります。 |
t
| 読み取り元のサンプリングまたは深度テクスチャー。 |
s
| サンプラー型。 |
coords
| テクスチャー座標。 |
array_index
|
0 ベースのテクスチャー配列インデックス。 この値は範囲 [0, textureNumLayers(t) - 1] にクランプされます。
|
offset
|
テクスチャーをサンプリングする前に、非正規化テクスチャー座標へ適用される任意のテクセルオフセット。
このオフセットは、テクスチャーのラップモードを適用する前に
適用されます。offset 式は必ずconst 式(たとえば
vec2<i32>(1, 2))でなければなりません。各 offset 成分は必ず -8 以上
7 以下でなければなりません。この範囲外の値はシェーダー作成エラーになります。
|
戻り値:
上記のように、選択されたテクセルの指定されたチャンネルから抽出された成分を持つ 4 成分ベクトル。
@group ( 0 ) @binding ( 0 ) var t : texture_2d< f32> ; @group ( 0 ) @binding ( 1 ) var dt : texture_depth_2d; @group ( 0 ) @binding ( 2 ) var s : sampler; fn gather_x_components ( c : vec2< f32> ) -> vec4< f32> { return textureGather ( 0 , t , s , c ); } fn gather_y_components ( c : vec2< f32> ) -> vec4< f32> { return textureGather ( 1 , t , s , c ); } fn gather_z_components ( c : vec2< f32> ) -> vec4< f32> { return textureGather ( 2 , t , s , c ); } fn gather_depth_components ( c : vec2< f32> ) -> vec4< f32> { return textureGather ( dt , s , c ); }
17.7.3.
textureGatherCompare
テクスチャーギャザー 比較操作は、深度テクスチャー内の 4 つのテクセルに対して深度比較を実行し、 次のように結果を単一のベクトルに収集します:
-
線形フィルタリングを使用する深度サンプリング操作で使用される 4 つのテクセルを、 ミップレベル 0 から見つけます:
-
指定された座標、配列インデックス(存在する場合)、およびオフセット(存在する場合)を使用します。
-
テクセルは、テクスチャー空間座標 (u,v) で見ると隣接し、正方形を形成します。
-
テクスチャー端、キューブ面の端、またはキューブの角で選択されたテクセルは、 通常のテクスチャーサンプリングと同様に処理されます。
-
-
各テクセルについて、比較サンプラーのパラメーターによる制御に従って深度参照値との比較を実行し、 0.0 または 1.0 の値を生成します。
-
成分が、次の相対テクセル座標を持つテクセルとの比較結果である 4 成分ベクトルを生成します:
-
結果の成分 相対テクセル座標 x (umin,vmax) y (umax,vmax) z (umax,vmin) w (umin,vmin)
-
| パラメーター化 | オーバーロード |
|---|---|
| |
| |
| A はi32、またはu32 |
|
| A はi32、またはu32 |
|
| |
| A はi32、またはu32 |
|
パラメーター:
t
| 読み取り元の深度テクスチャー。 |
s
| 比較サンプラー。 |
coords
| テクスチャー座標。 |
array_index
|
0 ベースのテクスチャー配列インデックス。 この値は範囲 [0, textureNumLayers(t) - 1] にクランプされます。
|
depth_ref
| サンプリングされた深度値と比較する参照値。 |
offset
|
テクスチャーをサンプリングする前に、非正規化テクスチャー座標へ適用される任意のテクセルオフセット。
このオフセットは、テクスチャーのラップモードを適用する前に
適用されます。offset 式は必ずconst 式(たとえば
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
マルチサンプリングテクスチャー内のテクセルあたりのサンプル数を返します。
| パラメーター化 | オーバーロード |
|---|---|
| ST はi32、u32、またはf32 T は texture_multisampled_2d<ST>
または texture_depth_multisampled_2d
|
|
パラメーター:
t
| マルチサンプリングテクスチャー。 |
戻り値:
17.7.8. textureSample
テクスチャーをサンプリングします。
必ず fragment シェーダーステージでのみ使用しなければなりません。
一様性 解析が、この関数の呼び出しが一様制御フロー内にあることを証明できない場合、 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 式は必ずconst 式(たとえば
vec2<i32>(1, 2))でなければなりません。各 offset 成分は必ず -8 以上
7 以下でなければなりません。この範囲外の値はシェーダー作成エラーになります。
|
戻り値:
サンプリングされた値。
17.7.9. textureSampleBias
ミップレベルにバイアスを加えてテクスチャーをサンプリングします。
必ず fragment シェーダーステージでのみ使用しなければなりません。
一様性 解析が、この関数の呼び出しが一様制御フロー内にあることを証明できない場合、 derivative_uniformity 診断がトリガーされます。
| パラメーター化 | オーバーロード |
|---|---|
| |
| |
| A はi32、またはu32 |
|
| A はi32、またはu32 |
|
T は texture_3d<f32>、または texture_cube<f32>
|
|
| |
| A はi32、またはu32 |
|
パラメーター:
t
| サンプリングするサンプリングテクスチャー。 |
s
| サンプラー型。 |
coords
| サンプリングに使用されるテクスチャー座標。 |
array_index
|
サンプリングする 0 ベースのテクスチャー配列インデックス。 この値は範囲 [0, textureNumLayers(t) - 1] にクランプされます。
|
bias
|
サンプリング前にミップレベルへ適用するバイアス。 この値は範囲 [-16.0, 15.99] にクランプされます。
|
offset
|
テクスチャーをサンプリングする前に、非正規化テクスチャー座標へ適用される任意のテクセルオフセット。
このオフセットは、テクスチャーのラップモードを適用する前に
適用されます。offset 式は必ずconst 式(たとえば
vec2<i32>(1, 2))でなければなりません。各 offset 成分は必ず -8 以上
7 以下でなければなりません。この範囲外の値はシェーダー作成エラーになります。
|
戻り値:
サンプリングされた値。
17.7.10.
textureSampleCompare
深度 テクスチャーをサンプリングし、サンプリングされた深度値を参照値と比較します。
必ず fragment シェーダーステージでのみ使用しなければなりません。
一様性 解析が、この関数の呼び出しが一様制御フロー内にあることを証明できない場合、 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 式(たとえば
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 式(たとえば
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
| サンプラー。 |
coords
| サンプリングに使用されるテクスチャー座標。 |
array_index
|
サンプリングする 0 ベースのテクスチャー配列インデックス。 この値は必ず範囲 [0, textureNumLayers(t) - 1] にクランプされます。
|
ddx
| サンプリング位置の計算に使用される x 方向の微分ベクトル。 |
ddy
| サンプリング位置の計算に使用される y 方向の微分ベクトル。 |
offset
|
テクスチャーをサンプリングする前に、非正規化テクスチャー座標へ適用される任意のテクセルオフセット。
このオフセットは、任意の
テクスチャーラップモードを適用する前に適用されます。offset 式は必ずconst 式(たとえば
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
| サンプラー型。 |
coords
| サンプリングに使用されるテクスチャー座標。 |
array_index
|
サンプリングする 0 ベースのテクスチャー配列インデックス。 この値は必ず範囲 [0, textureNumLayers(t) - 1] にクランプされます。
|
level
|
ミップレベル。レベル 0 にはテクスチャーのフルサイズ版が含まれます。
level が f32 である関数では、フォーマットが
テクスチャーフォーマット機能に従ってフィルター可能である場合、端数値によって
2 つのレベル間を補間してもよいです。
|
offset
|
テクスチャーをサンプリングする前に、非正規化テクスチャー座標へ適用される任意のテクセルオフセット。
このオフセットは、任意の
テクスチャーラップモードを適用する前に適用されます。offset 式は必ずconst 式(たとえば
vec2<i32>(1, 2))でなければなりません。各 offset 成分は必ず少なくとも -8、かつ最大
7 でなければなりません。範囲外の値は
シェーダー作成エラーになります。
|
戻り値:
サンプリングされた値。
17.7.14.
textureSampleBaseClampToEdge
テクスチャービューをそのベースレベルでサンプリングし、 テクスチャー座標を以下で説明するように端へクランプします。
| パラメーター化 | オーバーロード |
|---|---|
T は texture_2d<f32> または texture_external
|
|
パラメーター:
t
| サンプリングするサンプリングまたは外部テクスチャー。 |
s
| サンプラー型。 |
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 メモリー
順序付けを使用します。これは、同期および順序付けの保証が、同じメモリー位置に作用する
アトミック操作間にのみ適用されることを意味します。アトミックと非アトミックのメモリーアクセス間、または
異なるメモリー位置に作用するアトミックアクセス間には、同期
または順序付けの保証は適用されません。
アトミック組み込み関数は使用してはならず、vertex シェーダーステージでは使用できません。
すべてのアトミック組み込み関数における atomic_ptr パラメーターのアドレス空間 AS は
必ず storage
または workgroup のいずれかでなければなりません。
別途指定されない限り、T は必ず u32 または i32 のいずれかでなければなりません。
17.8.1. atomicLoad
fn atomicLoad ( atomic_ptr : ptr< AS , atomic< T > , read_write> ) -> T
atomic_ptr が指す値をアトミックにロードして返します。
オブジェクトを変更
しません。
17.8.2. atomicStore
fn atomicStore ( atomic_ptr : ptr< AS , atomic< T > , read_write> , v : T )
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 を用いた加算演算をアトミックに実行し、演算前にアトミックオブジェクトへ格納されていた
元の値を返します。
// すべての操作はアトミックに実行される fn atomicAdd ( atomic_ptr : ptr< AS , atomic< T > , read_write> , v : T ) -> T { let old = * atomic_ptr ; * atomic_ptr = old + v ; return old ; }
17.8.3.2. atomicSub
fn atomicSub ( atomic_ptr : ptr< AS , atomic< T > , read_write> , v : T ) -> T
atomic_ptr が指すアトミックオブジェクトに対して
値 v を用いた減算演算をアトミックに実行し、演算前にアトミックオブジェクトへ格納されていた
元の値を返します。
// すべての操作はアトミックに実行される fn atomicSub ( atomic_ptr : ptr< AS , atomic< T > , read_write> , v : T ) -> T { let old = * atomic_ptr ; * atomic_ptr = old - v ; return old ; }
17.8.3.3. atomicMax
fn atomicMax ( atomic_ptr : ptr< AS , atomic< T > , read_write> , v : T ) -> T
atomic_ptr が指すアトミックオブジェクトに対して
値 v を用いた最大値演算をアトミックに実行し、演算前にアトミックオブジェクトへ格納されていた
元の値を返します。
// すべての操作はアトミックに実行される fn atomicMax ( atomic_ptr : ptr< AS , atomic< T > , read_write> , v : T ) -> T { let old = * atomic_ptr ; * atomic_ptr = max ( old , v ); return old ; }
17.8.3.4. atomicMin
fn atomicMin ( atomic_ptr : ptr< AS , atomic< T > , read_write> , v : T ) -> T
atomic_ptr が指すアトミックオブジェクトに対して
値 v を用いた最小値演算をアトミックに実行し、演算前にアトミックオブジェクトへ格納されていた
元の値を返します。
// すべての操作はアトミックに実行される fn atomicMin ( atomic_ptr : ptr< AS , atomic< T > , read_write> , v : T ) -> T { let old = * atomic_ptr ; * atomic_ptr = min ( old , v ); return old ; }
17.8.3.5. atomicAnd
fn atomicAnd ( atomic_ptr : ptr< AS , atomic< T > , read_write> , v : T ) -> T
atomic_ptr が指すアトミックオブジェクトに対して
値 v を用いたビット単位 AND 演算をアトミックに実行し、演算前にアトミックオブジェクトへ格納されていた
元の値を返します。
// すべての操作はアトミックに実行される fn atomicAnd ( atomic_ptr : ptr< AS , atomic< T > , read_write> , v : T ) -> T { let old = * atomic_ptr ; * atomic_ptr = old & v ; return old ; }
17.8.3.6. atomicOr
fn atomicOr ( atomic_ptr : ptr< AS , atomic< T > , read_write> , v : T ) -> T
atomic_ptr が指すアトミックオブジェクトに対して
値 v を用いたビット単位 OR 演算をアトミックに実行し、演算前にアトミックオブジェクトへ格納されていた
元の値を返します。
// すべての操作はアトミックに実行される fn atomicOr ( atomic_ptr : ptr< AS , atomic< T > , read_write> , v : T ) -> T { let old = * atomic_ptr ; * atomic_ptr = old | v ; return old ; }
17.8.3.7. atomicXor
fn atomicXor ( atomic_ptr : ptr< AS , atomic< T > , read_write> , v : T ) -> T
atomic_ptr が指すアトミックオブジェクトに対して
値 v を用いたビット単位 XOR 演算をアトミックに実行し、演算前にアトミックオブジェクトへ格納されていた
元の値を返します。
// すべての操作はアトミックに実行される fn atomicXor ( atomic_ptr : ptr< AS , atomic< T > , read_write> , v : T ) -> T { let old = * atomic_ptr ; * atomic_ptr = old ^ v ; return old ; }
17.8.4. atomicExchange
fn atomicExchange ( atomic_ptr : ptr< AS , atomic< T > , read_write> , v : T ) -> T
atomic_ptr が指すアトミックオブジェクトに値 v をアトミックに格納し、
演算前にアトミックオブジェクトへ格納されていた元の値を返します。
// すべての操作はアトミックに実行される fn atomicExchange ( atomic_ptr : ptr< AS , atomic< T > , read_write> , v : T ) -> T { let old = * atomic_ptr ; * atomic_ptr = v ; return old ; }
17.8.5.
atomicCompareExchangeWeak
fn atomicCompareExchangeWeak ( atomic_ptr : ptr< AS , atomic< T > , read_write> , cmp : T , v : T ) -> __atomic_compare_exchange_result < T > struct __atomic_compare_exchange_result < T > { old_value : T , // アトミックに格納されていた古い値 exchanged : bool// 交換が行われた場合は true }
注: 値を
型
__atomic_compare_exchange_result で明示的に宣言することはできませんが、値はその型を推論できます。
次の手順をアトミックに実行します:
-
atomic_ptrが指す元の値をロードします。 -
等価演算を使用して、元の値と値
cmpを比較します。 -
等価比較の結果が
trueである場合にのみ値vを格納します。
2 メンバーの構造体を返します。最初のメンバー old_value は
演算前のアトミックオブジェクトの元の値であり、2 番目のメンバー exchanged は
比較が成功したかどうかを表します。
// すべての操作はアトミックに実行される fn atomicCompareExchangeWeak ( atomic_ptr : ptr< AS , atomic< T > , read_write> , cmp : T , v : T ) -> _atomic_compare_exchange_result < T > { let old = * atomic_ptr ; // この比較は見かけ上失敗する場合がある。 let comparison = old == cmp ; if comparison { * atomic_ptr = v ; } return __atomic_compare_exchange_result < T > ( old , comparison ); }
注: 等価比較は
一部の実装では見かけ上失敗する場合があります。つまり、
結果構造体の exchanged メンバーは、old_value メンバーが cmp と等しい場合でも
false になることがあります。
17.8.6. アトミック格納最小値および最大値関数
これらの関数はすべて atomic_vec2u_min_max 言語機能を必要とします。
これらの関数は値を返しません。
17.8.6.1.
atomicStoreMin
fn atomicStoreMin ( atomic_ptr : ptr< storage, atomic< vec2< u32>> , read_write> , v : vec2< u32> )
atomic_ptr が指すアトミックオブジェクトに対して 64 ビット符号なし整数の最小値演算をアトミックに実行し、
値 v
を使用します。
次の手順をアトミックに実行します:
-
atomic_ptr が参照するメモリーから元の vec2u 値 old をロードします。
-
64 ビット符号なし整数値を計算します:
-
old64 = 232 × old[1] + old[0]
-
v64 = 232 × v[1] + v[0]
-
-
old64 と v64 の最小値として値 new64 を計算します。
-
型 vec2<u32> の値 new を計算します。ここで:
-
new[0] は new64 の下位 32 ビットを含み、
-
new[1] は new64 の上位 32 ビットを含みます。
-
-
new を atomic_ptr が参照するメモリーへ格納します。
17.8.6.2.
atomicStoreMax
fn atomicStoreMax ( atomic_ptr : ptr< storage, atomic< vec2< u32>> , read_write> , v : vec2< u32> )
atomic_ptr が指すアトミックオブジェクトに対して 64 ビット符号なし整数の最大値演算をアトミックに実行し、
値 v
を使用します。
次の手順をアトミックに実行します:
-
atomic_ptr が参照するメモリーから元の vec2u 値 old をロードします。
-
64 ビット符号なし整数値を計算します:
-
old64 = 232 × old[1] + old[0]
-
v64 = 232 × v[1] + v[0]
-
-
old64 と v64 の最大値として値 new64 を計算します。
-
型 vec2<u32> の値 new を計算します。ここで:
-
new[0] は new64 の下位 32 ビットを含み、
-
new[1] は new64 の上位 32 ビットを含みます。
-
-
new を atomic_ptr が参照するメモリーへ格納します。
17.9. データパッキング組み込み関数
データパッキング組み込み関数は、WGSL の型に直接対応しない データフォーマットを使用して値をエンコードするために使用できます。 これにより、プログラムは多数の密にパックされた値をメモリーへ書き込むことができ、 シェーダーのメモリー帯域幅要求を削減できます。
各組み込み関数は、複数の入力値にチャンネル伝達関数の逆を適用し、その後 その結果を 単一の出力値へ結合します。
注: unorm 値をパックする場合、正規化された浮動 小数点値は区間 [0.0, 1.0] にあります。
注: snorm 値をパックする場合、正規化された浮動 小数点値は区間 [-1.0, 1.0] にあります。
17.9.1.
pack4x8snorm
| オーバーロード |
|
| 説明 |
4 つの正規化浮動小数点値を 8 ビット符号付き整数に変換し、その後それらを
1 つの u32 値へ結合します。
入力の成分 |
17.9.2.
pack4x8unorm
| オーバーロード |
|
| 説明 |
4 つの正規化浮動小数点値を 8 ビット符号なし整数に変換し、その後それらを
1 つの u32 値へ
結合します。
入力の成分 |
17.9.3. pack4xI8
| オーバーロード |
|
| 説明 |
e の各成分の下位 8 ビットを u32
値へパックし、使用されないすべてのビットを破棄します。
入力の成分 |
17.9.4. pack4xU8
| オーバーロード |
|
| 説明 |
e の各成分の下位 8 ビットを u32
値へパックし、使用されないすべてのビットを破棄します。
入力の成分 |
17.9.5.
pack4xI8Clamp
| オーバーロード |
|
| 説明 |
e の各成分を範囲 [-128, 127] にクランプし、その後各
成分の下位 8 ビットを u32 値へパックします。
入力の成分 |
17.9.6.
pack4xU8Clamp
| オーバーロード |
|
| 説明 |
e の各成分を範囲 [0, 255] にクランプし、その後各
成分の下位 8 ビットを u32 値へパックします。
入力の成分 |
17.9.7.
pack2x16snorm
| オーバーロード |
|
| 説明 | 2 つの正規化浮動小数点値を 16 ビット符号付き整数に変換し、その後それらを
1 つの u32 値へ結合します。入力の成分 e[i] は 16 ビット 2 の補数整数値へ変換されます
⌊ 0.5 + 32767 × min(1, max(-1, e[i])) ⌋。その後、結果のビット
16 × i から
16 × i + 15 に配置されます。
|
17.9.8.
pack2x16unorm
| オーバーロード |
|
| 説明 | 2 つの正規化浮動小数点値を 16 ビット符号なし整数に変換し、その後
それらを
1 つの u32 値へ結合します。入力の成分 e[i] は 16 ビット符号なし整数値へ変換されます
⌊ 0.5 + 65535 × min(1, max(0, e[i])) ⌋。その後、結果のビット
16 × i から
16 × i + 15 に配置されます。
|
17.9.9.
pack2x16float
| オーバーロード |
|
| 説明 |
2 つの浮動小数点値を半精度浮動小数点数へ変換し、その後それらを
1 つの u32 値へ結合します。入力の成分 e[i] は IEEE-754 binary16
値へ変換され、その後
結果のビット
16 × i から
16 × i + 15 に配置されます。
§ 15.7.6 浮動小数点変換を参照してください。
|
17.10. データアンパッキング組み込み関数
データアンパッキング組み込み関数は、 WGSL の型に直接対応しないデータフォーマットの値をデコードするために使用できます。 これにより、プログラムは多数の密にパックされた値をメモリーから読み取ることができ、 シェーダーのメモリー帯域幅要求を削減できます。
各組み込み関数は入力値をチャンネルへ分解し、その後それぞれにチャンネル伝達関数 を適用します。
注: unorm 値をアンパックする場合、正規化された 浮動小数点結果は区間 [0.0, 1.0] にあります。
注: snorm 値をアンパックする場合、正規化された 浮動小数点結果は区間 [-1.0, 1.0] にあります。
17.10.1.
unpack4x8snorm
| オーバーロード |
|
| 説明 | 32 ビット値を 4 つの 8 ビットチャンクへ分解し、その後
各チャンクを符号付き正規化浮動小数点値として再解釈します。 結果の成分 i は max(v ÷ 127, -1) です。ここで v は、
e のビット 8×i から 8×i + 7 を 2 の補数の符号付き
整数として解釈した値です。
|
17.10.2.
unpack4x8unorm
| オーバーロード |
|
| 説明 | 32 ビット値を 4 つの 8 ビットチャンクへ分解し、その後
各チャンクを符号なし正規化浮動小数点値として再解釈します。 結果の成分 i は v ÷ 255 です。ここで v は、
e のビット 8×i から 8×i + 7 を符号なし整数として解釈した値です。
|
17.10.3.
unpack4xI8
| オーバーロード |
|
| 説明 | e は 4 つの 8 ビット符号付き整数成分を持つベクトルとして解釈されます。
e を符号拡張して vec4<i32> へアンパックします。
|
17.10.4.
unpack4xU8
| オーバーロード |
|
| 説明 | e は 4 つの 8 ビット符号なし整数成分を持つベクトルとして解釈されます。
e をゼロ拡張して vec4<u32> へアンパックします。
|
17.10.5.
unpack2x16snorm
| オーバーロード |
|
| 説明 | 32 ビット値を 2 つの 16 ビットチャンクへ分解し、その後
各チャンクを符号付き正規化浮動小数点値として再解釈します。 結果の成分 i は max(v ÷ 32767, -1) です。ここで v は、
e のビット 16×i から 16×i + 15 を 2 の補数の
符号付き整数として解釈した値です。
|
17.10.6.
unpack2x16unorm
| オーバーロード |
|
| 説明 | 32 ビット値を 2 つの 16 ビットチャンクへ分解し、その後
各チャンクを符号なし正規化浮動小数点値として再解釈します。 結果の成分 i は v ÷ 65535 です。ここで v は、
e のビット 16×i から 16×i + 15 を符号なし整数として解釈した値です。
|
17.10.7.
unpack2x16float
| オーバーロード |
|
| 説明 | 32 ビット値を 2 つの 16 ビットチャンクへ分解し、各チャンクを
浮動小数点値として再解釈します。 結果の成分 i は v の f32 表現です。
ここで v は e のビット 16×i から
16×i + 15 を
IEEE-754 binary16
値として解釈したものです。
§ 15.7.6 浮動小数点変換を参照してください。
|
17.11. 同期組み込み関数
すべての同期関数は、Acquire/Release メモリー順序付けを伴う制御バリアを実行します。 すなわち、すべての同期関数、および影響を受けるメモリー操作とアトミック 操作は、同期関数に対してプログラム順序で順序付けられます。 さらに、同期関数より前にプログラム順序付けされた影響対象のメモリー操作とアトミック操作は、 同期関数より後にプログラム順序付けされた影響対象のメモリー操作またはアトミック操作が ワークグループのメンバーによって実行される前に、 ワークグループ内の他のすべてのスレッドから可視でなければなりません。
すべての同期関数は Workgroup メモリースコープを使用します。
すべての同期関数は Workgroup 実行スコープを持ちます。
すべての同期関数は必ず
compute シェーダーステージでのみ使用しなければなりません。
すべての同期関数は必ず
一様制御
フロー内でのみ呼び出されなければなりません。
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. サブグループ組み込み関数
§ 15.6.3 サブグループ操作を参照してください。
これらの関数の呼び出しは:
-
一様性解析が 呼び出しが一様制御フロー内にあることを証明できない場合、トリガーします。subgroup_uniformity 診断を。
注: compute シェーダーステージでは、一様制御フローのスコープは ワークグループです。 fragment シェーダーステージでは、一様制御フローのスコープは 描画コマンドです。 これらのスコープはいずれもサブグループより大きくなります。
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 診断を。
注: compute シェーダーステージでは、一様制御フローのスコープは ワークグループです。 fragment シェーダーステージでは、一様制御フローのスコープは 描画コマンドです。 これらのスコープはいずれもクアッドより大きくなります。
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 がランタイムサイズ配列である場合、 StrideOf(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 > ) { // データの一部を vec4u として読み書きする。 let p1 = bufferView < vec4u> ( & in , offsets [ 0 ]); * bufferView < vec4u> ( & out , offsets [ 1 ]) = * p1 ; // 構造体を介してほかのデータの一部を読み書きする。 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) { // in からストライド付き配列を読み取り、ストライドなしで 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) パーサーに適した形式で規定されています。 実装では代わりに再帰下降パーサーを使用したい場合があります。
規範的な文法は再帰下降パーサーで直接使用できません。これは、 その規則のいくつかが左再帰であるためです。 文法規則は、定義される非終端記号がその生成規則の 1 つの先頭に現れる場合、 直接左再帰です。
以下は WGSL 文法ですが、機械的に次のように変換されています:
-
直接および間接の左再帰を除去します。
-
空の生成規則を避けます。(すなわち、イプシロン規則を避けます。)
-
兄弟生成規則間の共通接頭辞をまとめます。
ただし、これは LL(1) ではありません。
一部の非終端記号では、複数の生成規則が共通の先読み集合を持ちます。
たとえば、attribute 非終端記号のすべての生成規則は attr
トークンで始まります。
より微妙な例は global_decl で、3 つの生成規則が
attribute *
句で始まりますが、その後 fn、override、var トークンによって区別されます。
簡潔にするため、多くのトークン定義は繰り返していません。 仕様の本文にあるトークン定義を使用してください。
'+'
| '-'
'(' ( expression ( ',' expression )* ',' ? )?
')'
| '='
| '@' ident_pattern_token ( '(' ( expression ( ',' expression )* ',' ? )?
')' )?
| '@' 'align' '(' expression ',' ? ')'
| '@' 'binding' '(' expression ',' ? ')'
| '@' 'blend_src' '(' expression ',' ? ')'
| '@' 'builtin' '(' builtin_value_name ',' ?
')'
| '@' 'diagnostic' diagnostic_control
| '@' 'group' '(' expression ',' ? ')'
| '@' 'id' '(' expression ',' ? ')'
| '@' 'location' '(' expression ',' ? ')'
| '@' 'size' '(' expression ',' ?
')'
| '@' 'subgroup_size' '(' expression ',' ?
')'
'&' unary_expression ( '&'
unary_expression )*
| '^' unary_expression ( '^' unary_expression )*
| '|' unary_expression ( '|' unary_expression )*
'false'
| 'true'
template_elaborated_ident.post.ident
'(' ( expression ( ',' expression )* ',' ? )?
')'
| 'default'
'.' member_ident component_or_swizzle_specifier
?
| '.' swizzle_name component_or_swizzle_specifier
?
| '[' expression ']' component_or_swizzle_specifier
?
| '%='
| '&='
| '*='
| '+='
| '-='
| '/='
| '^='
| '|='
'@' 'compute'
'@' 'const'
/0[iu]?/
| /[1-9][0-9]*[iu]?/
'(' ident_pattern_token ',' diagnostic_rule_name ','
? ')'
unary_expression bitwise_expression.post.unary_expression
| unary_expression relational_expression.post.unary_expression
| unary_expression relational_expression.post.unary_expression
'&&' unary_expression relational_expression.post.unary_expression
( '&&' unary_expression relational_expression.post.unary_expression
)*
| unary_expression relational_expression.post.unary_expression
'||' unary_expression relational_expression.post.unary_expression
( '||' unary_expression relational_expression.post.unary_expression
)*
'@' 'fragment'
'const_assert' ';'
attribute * 'fn' ident '(' ( attribute * ident
':' type_specifier ( ',' param )* ',' ? )? ')' (
'->' attribute * ident template_elaborated_ident.post.ident
)? attribute * '{' statement * '}'
| attribute * 'var' ( _template_args_start expression ( ',' expression )* ',' ? _template_args_end )? optionally_typed_ident (
'=' expression )? ';'
| global_value_decl ';'
| 'alias' ident '=' ident template_elaborated_ident.post.ident
';'
| 'struct' ident '{' attribute * member_ident ':' type_specifier ( ',' attribute * member_ident ':' type_specifier )* ',' ?
'}'
'diagnostic' '(' ident_pattern_token ',' diagnostic_rule_name
',' ? ')' ';'
| 'enable' ident_pattern_token ( ',' ident_pattern_token )* ',' ?
';'
| 'requires' ident_pattern_token ( ',' ident_pattern_token )* ',' ?
';'
attribute * 'override' optionally_typed_ident (
'=' expression )?
| 'const' optionally_typed_ident
'=' expression
'@' 'interpolate' '(' ident_pattern_token
',' ? ')'
| '@' 'interpolate' '(' ident_pattern_token
',' ident_pattern_token ',' ?
')'
'@' 'invariant'
core_lhs_expression component_or_swizzle_specifier ?
| '&' lhs_expression
| '*' lhs_expression
'%'
| '*'
| '/'
'@' 'must_use'
ident ( ':' type_specifier )?
attribute * ident
':' type_specifier
ident template_elaborated_ident.post.ident
| ident template_elaborated_ident.post.ident argument_expression_list
| literal
| '(' expression ')'
shift_expression.post.unary_expression
| shift_expression.post.unary_expression greater_than unary_expression shift_expression.post.unary_expression
| shift_expression.post.unary_expression greater_than_equal unary_expression shift_expression.post.unary_expression
| shift_expression.post.unary_expression less_than unary_expression shift_expression.post.unary_expression
| shift_expression.post.unary_expression less_than_equal unary_expression shift_expression.post.unary_expression
| shift_expression.post.unary_expression
'!=' unary_expression shift_expression.post.unary_expression
| shift_expression.post.unary_expression
'==' unary_expression shift_expression.post.unary_expression
( multiplicative_operator unary_expression )* ( additive_operator unary_expression ( multiplicative_operator unary_expression )* )*
attribute * 'for'
'(' for_init ? ';' expression ? ';' for_update ? ')' compound_statement
| attribute * 'if' expression compound_statement (
'else' 'if' expression compound_statement )* (
'else' compound_statement )?
| attribute * 'loop' attribute * '{' statement * ( 'continuing' attribute * '{' statement * ( 'break'
'if' expression ';' )?
'}' )? '}'
| attribute * 'switch' expression attribute * '{' switch_clause * '}'
| attribute * 'while' expression compound_statement
| ident template_elaborated_ident.post.ident
argument_expression_list
';'
| variable_or_value_statement
';'
| variable_updating_statement
';'
| assert_statement ';'
| break_statement ';'
| continue_statement ';'
| ';'
| 'discard' ';'
| 'return' expression ? ';'
'case' case_selector ( ',' case_selector )* ',' ?
':' ? compound_statement
| 'default' ':' ? compound_statement
/[rgba]/
| /[rgba][rgba]/
| /[rgba][rgba][rgba]/
| /[rgba][rgba][rgba][rgba]/
| /[xyzw]/
| /[xyzw][xyzw]/
| /[xyzw][xyzw][xyzw]/
| /[xyzw][xyzw][xyzw][xyzw]/
( _template_args_start template_arg_expression (
',' expression )* ',' ? _template_args_end )?
global_directive * ( global_decl | global_assert | ';' ) *
ident ( _template_args_start template_arg_expression (
',' expression )* ',' ? _template_args_end )?
primary_expression component_or_swizzle_specifier ?
| '!' unary_expression
| '&' unary_expression
| '*' unary_expression
| '-' unary_expression
| '~' unary_expression
'var' ( _template_args_start expression ( ',' expression )* ',' ? _template_args_end )? optionally_typed_ident
| variable_decl '=' expression
| 'const' optionally_typed_ident
'=' expression
| 'let' optionally_typed_ident
'=' expression
lhs_expression ( '=' | compound_assignment_operator
) expression
| lhs_expression '++'
| lhs_expression '--'
| '_' '=' expression
'@' 'vertex'
'@' 'workgroup_size' '(' expression ',' ?
')'
| '@' 'workgroup_size' '(' expression ',' expression ',' ?
')'
| '@' 'workgroup_size' '(' expression ',' expression ',' expression ',' ?
')'
付録 A:
text/wgsl メディアタイプ
Internet Assigned Numbers Authority(IANA)は、[IANA-MEDIA-TYPES] にメディアタイプのレジストリを維持しています。
以下は WGSL モジュール用の text/wgsl メディアタイプの定義です。
これは IANA に登録されており、
https://www.iana.org/assignments/media-types/text/wgsl
に掲載されています。
- 型名
-
text
- サブタイプ名
-
wgsl
- 必須パラメーター
-
N/A
- 任意パラメーター
-
なし
- エンコーディング上の考慮事項
-
binary
WGSL は UTF-8 エンコーディングを使用する Unicode テキストであり、バイトオーダーマーク(BOM)はありません。 § 3 テキスト構造を参照してください。
- セキュリティ上の考慮事項:
-
WebGPU Shading Language(WGSL)は、WebGPU API のコンテキストで実行される GPU コード用のプログラミング言語です。セキュリティ上の 考慮事項については、[WebGPU] 2.1 節「セキュリティ上の考慮事項」を参照してください。 プライバシー上の考慮事項については、[WebGPU] 2.2 節「プライバシー上の 考慮事項」を参照してください。
- 相互運用性上の考慮事項:
-
WebGPU の実装は異なる機能を持つ場合があり、 これらの違いは WGSL プログラムで利用できる機能に影響する可能性があります。 [WebGPU] 3.6 節「任意機能」、 および § 4.1.2 言語拡張を参照してください。
実装は、この 登録が WGSL の後続版にも適用されるかのように動作することが期待され、その公開された 仕様参照はそれに応じて随時更新される場合があります。 この期待はメディアタイプ登録としては珍しいものですが、 広く普及している業界慣行と一致しています。
- 公開仕様:
-
WebGPU Shading Language
- このメディアタイプを使用するアプリケーション:
-
WebGPU の実装。これにはウェブブラウザーが含まれることが期待されます。
- フラグメント識別子に関する考慮事項
-
なし
- 追加情報:
-
マジックナンバー: なし
ファイル拡張子:
.wgslMacintosh ファイルタイプコード:
TEXT - 詳細情報の連絡先担当者およびメールアドレス:
-
David Neto, dneto@google.com、または WGSL に記載されている編集者。
- 想定用途
-
COMMON
- 著者
-
W3C。WGSL に記載されている編集者を参照してください。
- 変更管理者
-
W3C
- 規範的参考文献
-
[WebGPU] W3C, "WebGPU” W3C Working Draft, January 2023. https://w3.org/TR/webgpu
Webgpu Shading Language W3C, "WebGPU Shading Language" W3C Working Draft, January 2023. https://w3.org/TR/WGSL