WebGPUシェーディング言語

W3C勧告案ドラフト

この文書の詳細
このバージョン:
https://www.w3.org/TR/2025/CRD-WGSL-20251020/
最新公開バージョン:
https://www.w3.org/TR/WGSL/
編集者ドラフト:
https://gpuweb.github.io/gpuweb/wgsl/
以前のバージョン:
履歴:
https://www.w3.org/standards/history/WGSL/
フィードバック:
public-gpu@w3.org 件名 “[WGSL] … メッセージトピック …” (アーカイブ)
GitHub
編集者:
(Google)
(Google)
前編集者:
(Apple Inc.)
(Google)
参加:
Issueを提出 (未解決のIssue)
テストスイート:
WebGPU CTS shader/

概要

WebGPU用のシェーディング言語。

この文書のステータス

このセクションは、本書の公開時点でのステータスについて説明します。現行標準の一覧や本技術レポートの最新改訂版は、W3C標準およびドラフト一覧で確認できます。

この仕様へのフィードバックやコメントを歓迎します。 この仕様に関する議論は、GitHub Issuesが推奨されます。もしくは、GPU for the Webワーキンググループのメーリングリストpublic-gpu@w3.orgアーカイブ)までコメントを送ることもできます。 このドラフトには、ワーキンググループ内でまだ議論されている未解決の課題がいくつか示されています。 これらの課題の妥当性を含め、結果についてはまだ決定されていません。

この文書は、GPU for the Webワーキンググループにより、勧告トラックを使用してCandidate Recommendation Draftとして公開されました。 この文書は、少なくともまでCandidate Recommendationのままとなります。

グループは、各機能が最新GPUシステムAPI上の少なくとも2つの実際のブラウザで実装されていることを実証する予定です。テストスイートは実装レポートの作成に利用されます。

Candidate Recommendationとしての公開は、W3Cおよびそのメンバーによる承認を意味するものではありません。Candidate Recommendation Draftは、ワーキンググループが次のCandidate Recommendation Snapshotに含める予定の、前回のCandidate Recommendationからの変更を統合したものです。

この文書は随時管理・更新されます。一部はまだ作業中です。

この文書は、W3C特許ポリシーの下で活動するグループによって作成されました。W3Cは、グループの成果物に関連して行われた特許開示の公開リストを管理しています。そのページには特許開示の方法についての説明もあります。個人が、必須クレームを含むと信じる特許について実際の知識がある場合、W3C特許ポリシー第6節に従って情報を開示しなければなりません。

この文書は、2025年8月18日版W3Cプロセス文書に準拠して管理されています。

1. はじめに

WebGPUシェーディング言語(WGSL)は、[WebGPU]のためのシェーダー言語です。 つまり、WebGPU APIを使用するアプリケーションは、GPU上で実行されるプログラム(シェーダー)をWGSLで記述します。

// テクスチャ付きジオメトリを点光源で照らすフラグメントシェーダー。

// ストレージバッファバインディングからのライト。
struct PointLight {
  position : vec3f,
  color : vec3f,
}

struct LightStorage {
  pointCount : u32,
  point : array<PointLight>,
}
@group(0) @binding(0) var<storage> lights : LightStorage;

// テクスチャとサンプラー。
@group(1) @binding(0) var baseColorSampler : sampler;
@group(1) @binding(1) var baseColorTexture : texture_2d<f32>;

// 関数の引数は頂点シェーダーから渡される値。
@fragment
fn fragmentMain(@location(0) worldPos : vec3f,
                @location(1) normal : vec3f,
                @location(2) uv : vec2f) -> @location(0) vec4f {
  // テクスチャから表面の基本色をサンプルする。
  let baseColor = textureSample(baseColorTexture, baseColorSampler, uv);

  let N = normalize(normal);
  var surfaceColor = vec3f(0);

  // シーン内の点光源をループ処理。
  for (var i = 0u; i < lights.pointCount; i++) {
    let worldToLight = lights.point[i].position - worldPos;
    let dist = length(worldToLight);
    let dir = normalize(worldToLight);

    // このライトの表面色への寄与を算出。
    let radiance = lights.point[i].color * (1 / pow(dist, 2));
    let nDotL = max(dot(N, dir), 0);

    // 表面色にライトの寄与を加算。
    surfaceColor += baseColor.rgb * radiance * nDotL;
  }

  // 加算した表面色を返す。
  return vec4(surfaceColor, baseColor.a);
}

1.1. 概要

WebGPUは、GPUコマンドという形で作業単位をGPUに発行します。 WGSLは、2種類のGPUコマンドに関係します:

両方の種類のパイプラインで、WGSLで記述されたシェーダーが使われます。

シェーダーは、 WGSLプログラム内でパイプラインのシェーダーステージを実行する部分です。 シェーダーは次の要素で構成されます:

注意: WGSLプログラムはエントリーポイントを必須としません。ただし、エントリーポイントがないプログラムはAPIによって実行できません。なぜなら、エントリーポイントがGPUProgrammableStageの作成に必要だからです。

シェーダーステージを実行する際、実装は次の処理を行います:

WGSLプログラムは次の要素から構成されます:

注意: WGSLプログラムは現在、単一のWGSLモジュールで構成されます。

WGSLは命令型言語です。挙動は実行する文の列として記述します。 文は次のことができます:

WGSLは静的型付け言語です。各式で計算される値は、プログラムソースのみから決定される特定の型を持ちます。

WGSLにはブール値や数値(整数浮動小数点)を記述する型があります。 これらの型は複合型ベクトル行列配列構造体)に集約できます。 WGSLには、固有の操作を提供するアトミック型などの特殊な型があります。 WGSLはメモリに格納可能な型をメモリビューとして記述します。 WGSLはテクスチャやサンプラーなど、よく使われるレンダリング型も提供します。 これらの型には、グラフィックスレンダリングのためのGPUハードウェアを活用する組み込み関数が用意されています。

WGSLには、具体型からの暗黙の変換や昇格はありませんが、 抽象型からの暗黙の変換・昇格は許可されます。 ある具体型の数値型やブール型から他の型へ値を変換するには、 明示的な変換値コンストラクタビットの再解釈が必要です。ただし、WGSLはスカラー型からベクトル型への限定的な昇格機能を提供します。 これは複合型にも適用されます。

シェーダーステージの作業は、1つ以上の呼び出しに分割されます。 各呼び出しはエントリーポイントを実行しますが、状況が少し異なります。 シェーダーステージの呼び出しは、特定の変数へのアクセスを共有します:

ただし、呼び出しはステージ入力(同僚と区別する識別値を提供する組み込み入力を含む)の異なる集合に対して動作します。 各呼び出しは、privatefunctionアドレス空間の変数として独立したメモリ空間を持ちます。

同じシェーダーステージ内の呼び出しは同時に実行され、多くの場合並列で動作します。 シェーダー作成者は、呼び出しの動的な挙動が次を満たすよう責任を持ちます:

WGSLは、ある機能に対して複数の挙動を許容する場合があります。 これは移植性の問題となり、実装によって異なる挙動が現れることがあります。 WGSLの設計はそのようなケースを最小化することを目指していますが、実現可能性や幅広いデバイスで高性能を発揮するという目標に制約されることもあります。

挙動要件は、 WGSLプログラムの処理や実行時に実装が行うべきアクションです。これらは プログラマーとの契約における実装の義務を示します。 仕様書は、明らかでない場合に明示的にこれらの義務を記載します。

1.2. 構文記法

以下の構文記法はWGSLの構文文法規則の慣例を示します:

1.3. 数学的用語と記法

角度

双曲線角は、従来の角度ではなく単位のない面積です。具体的には:

この面積 a は双曲線角であり、xa の双曲線余弦、y は双曲線正弦となります。

正の無限大(+∞)はすべての実数より大きい固有の値です。

負の無限大(−∞)はすべての実数より小さい固有の値です。

拡張実数(またはアフィン拡張実数)は実数全体に+∞と−∞を加えた集合です。 コンピューターは浮動小数点型で拡張実数を近似表現し、両方の無限大値も含みます。 § 15.7 浮動小数点評価も参照してください。

区間は下限と上限を持つ連続した数値集合です。 文脈によって、整数・浮動小数点・実数・拡張実数集合の場合があります。

床関数は、拡張実数 x に対し:

天井関数は、拡張実数 x に対して:

切り捨て関数は、拡張実数 x に対して:

roundUp関数は、正の整数 kn に対し:

転置は、cr行の行列 Aを、rc行の行列 ATとして Aの行を ATの列へコピーすることで作られます:

列ベクトルの転置は1行の行列として解釈され、同様に行ベクトルの転置は1列の行列として解釈されます。

2. WGSLモジュール

WGSLプログラムは単一のWGSLモジュールから構成されます。

モジュールは、オプションのディレクティブの並びの後に、モジュールスコープ宣言およびアサーションが続きます。 モジュールは以下の要素で構成されます:

translation_unit :

global_directive * ( global_decl | global_assert | ';' ) *

global_decl :

global_variable_decl ';'

| global_value_decl ';'

| type_alias_decl ';'

| struct_decl

| function_decl

2.1. シェーダーのライフサイクル

WGSLプログラムとその中のシェーダーが経験するライフサイクルには、4つの主要なイベントがあります。 最初の2つはWGSLプログラムを実行準備するために使われるWebGPU APIメソッドに対応しています。 最後の2つはシェーダーの実行開始と終了です。

イベントは以下の通りです:

  1. シェーダーモジュール作成

    • これはWebGPU createShaderModule() メソッドが呼ばれたときに発生します。 WGSLプログラムのソーステキストはこの時点で提供されます。

  2. パイプライン作成

    • これはWebGPU createComputePipeline() メソッド またはWebGPU createRenderPipeline() メソッドが呼ばれたときに発生します。 これらのメソッドは、事前に作成された1つ以上のシェーダーモジュールと他の設定情報を使用します。

    • 指定されたエントリーポイントGPUProgrammableStageシェーダーを構成するコードのみがパイプライン作成時に考慮されます。 つまり、エントリーポイントに関係しないコードはコンパイル前に実質的に除去されます。

    • 注意:シェーダーステージは個別にコンパイルされるとみなされるため、 モジュールの異なる部分を含む場合があります。

  3. シェーダー実行開始

  4. シェーダー実行終了

    • これはシェーダー内のすべての処理が完了したときに発生します:

      • すべての呼び出しが終了し、

      • すべてのリソースへのアクセスが完了し、

      • 出力(ある場合)は下流のパイプラインステージに渡されます。

これらのイベントは次の理由で順序付けられます:

2.2. エラー

WebGPUの実装がシェーダーの処理に失敗する理由は2つあります:

処理エラーはシェーダーのライフサイクルの3段階で発生する場合があります:

注意: 例えば、データレースは検出できない場合があります。

各要件willは最も早く検出可能なタイミングでチェックされます。 つまり:

文脈からはっきりしない場合、この仕様書は 特定の要件の違反が シェーダー作成エラー・パイプライン作成エラー・動的エラーのどれにつながるかを明示します。

エラーの結果は以下の通りです:

2.3. 診断

実装はシェーダーモジュール作成またはパイプライン作成の間に診断を生成できます。 診断とは、実装がアプリケーション制作者のために出力するメッセージです。

診断は、特定の条件が満たされたときに作成またはトリガーされます。 この条件をトリガールールと呼びます。 条件が満たされたソーステキスト中の場所(点または範囲)は トリガー位置と呼ばれます。

診断は次のプロパティを持ちます:

診断の重大度は以下のいずれかであり、高い順に並んでいます:

error(エラー)

診断はエラーです。 これはシェーダー作成エラーまたはパイプライン作成エラーに相当します。

warning(警告)

診断は開発者の注意を促す異常を記述しますが、エラーではありません。

info(情報)

診断は開発者の注意を促す注目すべき状態を記述しますが、エラーでも警告でもありません。

off(無効)

診断は無効化されています。アプリケーションには通知されません。

トリガールールの名前は、以下のいずれかです:

diagnostic_rule_name :

diagnostic_name_token

| diagnostic_name_token '.' diagnostic_name_token

2.3.1. 診断処理

トリガーされた診断はwill次のように処理されます:

  1. 各診断Dについて、Dのトリガー位置を含み、かつ同じトリガールールを持つ最小の診断フィルターを探す。

    • そのようなフィルターが存在すれば、Dに適用し、D重大度を更新する。

    • 存在しなければDは変更されません。

  2. 重大度offの診断を破棄します。

  3. 残った診断のうち、少なくとも1つDIが重大度infoなら:

    • 同じトリガールールを持つ他のinfo診断は破棄されることがあり、元の診断DIのみが残ります。

  4. 残った診断のうち、少なくとも1つDWが重大度warningなら:

    • 同じトリガールールを持つ他のinfowarning診断は破棄されることがあり、元の診断DWのみが残ります。

  5. 残った診断にerror重大度がある場合:

  6. シェーダーモジュール作成時処理の場合、残った診断はWebGPU messages メンバーに格納されます(GPUCompilationInfoオブジェクト)。

  7. パイプライン作成時処理の場合、error診断はWebGPUの検証失敗につながります(GPUProgrammableStageの検証時)。

注意: これらの規則により、実装はエラーを検出した時点でWGSLモジュールの処理を打ち切ることができます。 また、ある種の警告分析は最初の警告で打ち切ることができ、ある種の情報診断分析も最初の発生で打ち切ることができます。 WGSLはさまざまな分析手順の順序や、単一分析内の順序を規定しません。 したがって、同じWGSLモジュールでも、異なる実装は同じ重大度の診断のインスタンスを異なる数だけ報告する場合があります。

2.3.2. フィルタ可能なトリガールール

ほとんどの診断は無条件でWebGPUアプリケーションに報告されます。 一部の診断は、フィルタ可能であり、トリガールールの名前付けにより部分的に制御できます。 以下の表はフィルタ可能な標準的トリガールールを示します。

フィルタ可能な診断トリガールール
フィルタ可能トリガールール デフォルト重大度 トリガー位置 説明
derivative_uniformity error 微分を計算する組み込み関数呼び出し位置。 つまり、以下への呼び出しの位置: 組み込み関数呼び出しで微分を計算するが、均一性解析がその呼び出しが均一な制御フロー内で発生することを証明できない場合。

§ 15.2 均一性も参照。

subgroup_uniformity error サブグループクアッド組み込み関数の呼び出し位置。 サブグループまたはクアッド組み込み関数呼び出しだが、均一性解析がその呼び出しが均一な制御フロー内で発生することを証明できない場合。 また、均一性解析が以下のパラメータ値の均一性を証明できない場合:

§ 15.2 均一性も参照。

1つのdiagnostic name-tokenで構成される認識されないトリガールールを使うと、ユーザーエージェントは警告をトリガーするべきです。

実装はここで定義されていないトリガールールもサポートしてよいですが、 diagnostic_rule_nameの複数トークン形式で記述されている必要があります。 未認識のトリガールールを複数トークン形式で記述した場合、それ自体が診断をトリガーすることがあります。

将来の仕様書バージョンでは、特定のルールを削除したり、デフォルト重大度を弱めたり(現在のデフォルトより軽くする)しても後方互換性を満たしたとみなされます。 例えば、WGSLの将来バージョンでderivative_uniformityのデフォルト重大度をerrorからwarningまたはinfoに変更することがあります。 このような仕様変更後も、以前は有効だったプログラムは引き続き有効です。

2.3.3. 診断フィルター

フィルタ可能なトリガールールを持つ診断トリガーされると、WGSLはその診断を破棄したり重大度を変更する仕組みを提供します。

診断フィルター DFは3つのパラメータを持ちます:

診断フィルターDF(AR,NS,TR)を診断Dに適用すると、以下の効果があります:

範囲診断フィルターは、 診断フィルターのうち、影響範囲が指定されたソーステキストの範囲であるものです。 範囲診断フィルターは、影響範囲の先頭に@diagnostic属性として指定します。 @diagnostic属性は他の場所には現れてはなりません。

範囲診断フィルターの配置
配置 影響範囲
複合文の先頭 その複合文
関数宣言の先頭 関数宣言
if文の先頭 if文:if_clauseおよび関連するelse_if_clauseelse_clause、制御条件式すべてを含む
switch文の先頭 switch文:セレクター式とswitch_body
switch_bodyの先頭 switch_body
loop文の先頭 loop文
while文の先頭 while文:条件式とループ本体両方
for文の先頭 for文:for_headerとループ本体
ループ本体の開始波括弧('{')直前 ループ本体
continuing_compound_statementの先頭 continuing_compound_statement

注意: 以下も複合文です: 関数本体case句default-alone句whileforループの本体、 if_clauseelse_if_clauseelse_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モジュール全体に診断フィルターを適用できます。

例:derivative_uniformityのグローバル診断フィルター
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)が 競合するのは以下の場合です:

診断フィルター競合してはなりません。

注意: 競合しない場合、複数のグローバル診断フィルターの利用が可能です。

WGSLの診断フィルターは、その影響範囲が完全に入れ子となるように設計されています。 DF1の影響範囲がDF2の影響範囲と重なる場合、DF1の影響範囲はDF2の影響範囲に完全に含まれるか、その逆です。

ソース位置LとトリガールールTRに対する最も近い囲み診断フィルター(存在する場合)は、DF(AR,NS,TR)で次を満たすものです:

影響範囲が入れ子になるため、最も近い囲み診断:

2.4. 制限

WGSLの実装は以下の制限を満たすシェーダーをサポートするwill必要があります。 WGSLの実装は、指定された制限を超えるシェーダーもサポートしてよいです。

注意: WGSL実装は、指定された制限を超えるシェーダーをサポートしない場合エラーを出すべきです。

定量可能なシェーダー複雑性の制限
制限 最低サポート値
構造体型のメンバー最大数 1023
複合型入れ子深度の最大値 15
関数内の波括弧で囲まれた文の最大入れ子深度 127
関数のパラメータ最大数 255
switch文のcaseセレクター値最大数。 各case文のcase値数およびdefault句の合計。 1023
privateアドレス空間で1つのシェーダーによって静的にアクセスされる変数すべての合計バイトサイズ最大値 8192
functionアドレス空間で1つの関数に宣言された変数すべての合計バイトサイズ最大値 8192
workgroupアドレス空間で1つのシェーダーによって静的にアクセスされる変数すべての合計バイトサイズ最大値

この制限のため、固定フットプリント配列は、オーバーライド値で置き換える際に作成時固定フットプリント配列として扱われます。

これはWebGPUのmaxComputeWorkgroupStorageSize 制限をWGSL独自の制限へマッピングします。

16384
value constructor式のarray型における要素最大数 2047

3. テキスト構造

text/wgslメディアタイプは、WGSLモジュールとしてコンテンツを識別するために使われます。 付録A: text/wgslメディアタイプを参照してください。

WGSLモジュールはUTF-8でエンコードされたUnicodeテキストで、バイトオーダーマーク(BOM)はありません。

WGSLモジュールのテキストは、Unicodeのコードポイントの並びであり、連続した空でない集合にグループ化されて以下を形成します:

プログラムテキストはヌルコードポイント(U+0000)を含んではなりません

3.1. 構文解析

WGSLモジュールを構文解析する手順:

  1. コメントを削除:

    • 最初のコメントをスペースコードポイント(U+0020)に置換。

    • コメントが残っている限り繰り返す。

  2. テンプレートリストを、 § 3.9 テンプレートリストのアルゴリズムで検出。

  3. 全文を、translation_unit構文規則にマッチさせて解析する。 解析にはLALR(1)パーサ(一つ先読み)[DeRemer1969]を使い、以下のカスタマイズがあります:

    • 字句解析(トークン化)は構文解析と交互に行われ、文脈依存です。 パーサが次のトークンを要求したとき:

次の場合はシェーダー作成エラーとなります:

3.2. 空白と改行

空白は、 UnicodeのPattern_White_Spaceプロパティのいずれかのコードポイント1つ以上の組み合わせです。 以下はPattern_White_Spaceに含まれるコードポイントの集合です:

改行は、 空白コードポイントの連続で、行の終端を示します。 これはUAX14 Section 6.1 Non-tailorable Line Breaking RulesLB4LB5で規定される「必須改行」です。 すなわち、改行となるのは以下のいずれかです:

注意: ソーステキストの行番号で報告する診断は、改行を使って行数を数えるべきです。

3.3. コメント

コメントは、 WGSLプログラムの妥当性や意味に影響しないテキスト範囲ですが、コメントはトークンを分離することができます。 シェーダー作者はコメントを使ってプログラムを記録できます。

行末コメントコメントの一種で、 次の2つのコードポイント//U+002FU+002F)と、その後に続くコードポイントからなります。 ただし、以下のいずれかまで(含まず):

ブロックコメントコメントの一種で、以下からなります:

注意: ブロックコメントは入れ子にできます。 ブロックコメントは開始と終了のテキスト一致が必要で、任意の入れ子を許すため、正規表現で認識することはできません。 これは正規言語のポンピング補題の帰結です。

例:コメント
const f = 1.5; // これは行末コメントです。
const g = 2.5; /* これは複数行にまたがるブロックコメントです
                /* ブロックコメントは入れ子にできます。
                 */
                ただしすべてのブロックコメントは終了しなければなりません。
               */

3.4. トークン

トークンは、以下のいずれかを構成する連続したコードポイントの並びです:

3.5. リテラル

リテラルは以下のいずれかです:

literal :

int_literal

| float_literal

| bool_literal

3.5.1. 真偽値リテラル

例:真偽値リテラル
const a = true;
const b = false;
bool_literal :

'true'

| 'false'

3.5.2. 数値リテラル

数値リテラルの形式はパターンマッチングで定義されます。

整数リテラルは以下の通り:

注意: 非ゼロ整数リテラルの先頭ゼロ(例:012)は禁止です。他言語の先頭ゼロ=8進数記法との混同を避けるためです。

int_literal :

decimal_int_literal

| hex_int_literal

decimal_int_literal :

/0[iu]?/

| /[1-9][0-9]*[iu]?/

例:10進整数リテラル
const a = 1u;
const b = 123;
const c = 0;
const d = 0i;
hex_int_literal :

/0[xX][0-9a-fA-F]+[iu]?/

例:16進整数リテラル
const a = 0x123;
const b = 0X123u;
const c = 0x3f;

浮動小数点リテラル10進浮動小数点リテラルまたは16進浮動小数点リテラルです。

float_literal :

decimal_float_literal

| hex_float_literal

浮動小数点リテラルは、分数を表す仮数部と、オプションの指数部の2つの論理部分を持ちます。 リテラルの値は概ね、仮数部を基数^指数の値で乗算したものです。 仮数部の数字は、ゼロでない場合、または左と右にゼロでない数字が両方ある場合、有効桁とみなされます。 有効桁は左から右へ数えます。N番目の有効桁は左にN-1個の有効桁があります。

10進浮動小数点リテラルは以下の通り:

decimal_float_literal :

/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]?/

例:10進浮動小数点リテラル
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;
10進浮動小数点リテラルの数学的値は以下で計算されます:

注意: 小数部は20桁以降切り捨て、約log(10)/log(2)×20 ≈ 66.4ビットの有効精度が保持されます。

16進浮動小数点リテラルは以下の通り:

hex_float_literal :

/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]?/

例:16進浮動小数点リテラル
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;
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

次の場合はシェーダー作成エラーとなります:

注意: 16進浮動小数点値0x1.00000001p0は正確に表すには33有効ビットが必要ですが、f32は明示的有効ビットが23しかありません。

注意: 16進floatリテラルを型指定したい場合、fサフィックスを使うなら2進指数も必要です。例:0x1p0f0x1fは16進整数リテラルです。

3.6. キーワード

キーワードは、あらかじめ定義された言語概念を指すトークンです。 WGSLキーワード一覧は§ 16.1 キーワード一覧を参照してください。

3.7. 識別子

識別子は、名前として使用されるトークンの一種です。 詳細は§ 5 宣言とスコープを参照してください。

WGSLは用途ごとに2つの文法非終端記号を使い分けています:

ident :

ident_pattern_token _disambiguate_template

member_ident :

ident_pattern_token

識別子の形式は、Unicode Standard Annex #31 (Unicode Version 14.0.0)に基づき、 以下の補足があります。

識別子はUAX31文法で次のプロファイルを使います:

<Identifier> := <Start> <Continue>* (<Medial> <Continue>+)*

<Start> := XID_Start + U+005F
<Continue> := <Start> + XID_Continue
<Medial> :=

つまり、非ASCIIコードポイントを含む識別子も有効です:ΔέλταréflexionКызыл𐰓𐰏𐰇朝焼けسلام検定שָׁלוֹםगुलाबीփիրուզなど。

ただし以下は例外です:

ident_pattern_token :

/([_\p{XID_Start}][\p{XID_Continue}]+)|([\p{XID_Start}])/u

Unicode Character Database for Unicode Version 14.0.0には XID_Startおよび XID_Continueの全有効コードポイントが非規範的に列挙されています。

注意: 一部の組み込み関数戻り値型は、名前がWGSLソースで使用できない構造体型です。 それらの構造体型は、名前がアンダースコア2文字で始まるものとして事前宣言されたものとみなされます。 結果値は新しく宣言したletvarに型推論で保存するか、そのメンバーを直接名前指定で抽出できます。 使用例はfrexpmodfの説明を参照してください。

3.7.1. 識別子の比較

2つのWGSL識別子は、同じコードポイントの並びである場合に限り同一です。

注意: この仕様では比較時のUnicode正規化を認めていません。 見た目や意味が同じでも、異なるUnicode文字列の並びであれば一致しません。 著者は値のエンコード順序を一貫して使うか、問題を起こしそうな文字を避けることが推奨されます。 詳細は[CHARMOD-NORM]参照。

注意: ユーザーエージェントは、識別子のすべての出現箇所を、その同形異義語(ホモグリフ)で置換した場合WGSLモジュールの意味が変わるとき、 開発者向け警告を出すべきです。 (ホモグリフとは、読者に同じに見える可能性のあるコードポイント列のこと。 マッピング検出例は前段落の変換・マッピング・照合アルゴリズムなど。 反復的に部分列をホモグリフで置換することで識別子を変換できる場合、2つの列は同形異義語とみなされます。)

3.8. 文脈依存名

文脈依存名は、特定の文法的文脈でのみ概念の名前として使われるトークンです。 トークンの綴りは識別子と同じ場合もありますが、そのトークンは宣言されたオブジェクトに解決されません。 このセクションでは、文脈依存名として使われるトークンを列挙します。 トークンはキーワード予約語であってはなりません。

3.8.1. 属性名

§ 12 属性を参照してください。

属性名:

3.8.2. 組み込み値名

組み込み値名トークンは、組み込み値の名前に使われるトークンです。

§ 13.3.1.1 組み込み入力・出力参照。

builtin_value_name :

ident_pattern_token

組み込み値名:

3.8.3. 診断ルール名

診断名トークンは、診断トリガールールの名前に使われるトークンです。

§ 2.3 診断参照。

diagnostic_name_token :

ident_pattern_token

あらかじめ定義された診断ルール名:

3.8.4. 診断重大度制御名

有効な診断フィルター重大度制御名は§ 2.3 診断に記載されていますが、形式は識別子と同じです:

severity_control_name :

ident_pattern_token

診断フィルター重大度制御名:

3.8.5. 拡張名

有効な拡張有効化名は§ 4.1.1 拡張の有効化に記載されていますが、一般的には識別子と同じ形式です:

enable_extension_name :

ident_pattern_token

拡張有効化名:

有効な言語拡張名は§ 4.1.2 言語拡張に記載されていますが、一般的には識別子と同じ形式です:

language_extension_name :

ident_pattern_token

言語拡張名:

3.8.6. 補間型名

補間型名トークンは、補間型の名前に使われるトークンです。 interpolate_type_name用。

§ 13.3.1.4 補間参照。

補間型名:

3.8.7. 補間サンプリング名

補間サンプリング名トークンは、補間サンプリングの名前に使われるトークンです。

§ 13.3.1.4 補間参照。

interpolate_sampling_name :

ident_pattern_token

補間サンプリング名:

3.8.8. スウィズル名

スウィズル名はベクトルアクセス式で使用されます:

swizzle_name :

/[rgba]/

| /[rgba][rgba]/

| /[rgba][rgba][rgba]/

| /[rgba][rgba][rgba][rgba]/

| /[xyzw]/

| /[xyzw][xyzw]/

| /[xyzw][xyzw][xyzw]/

| /[xyzw][xyzw][xyzw][xyzw]/

3.9. テンプレートリスト

テンプレートパラメータ化は、一般的な概念を修飾するためのパラメータを指定する方法です。 テンプレートパラメータ化を書くには、一般概念の後にテンプレートリストを書きます。

コメント空白を無視すると、テンプレートリストは:

テンプレートパラメータの形式は、下記のテンプレートリスト発見アルゴリズムで暗黙的に定義されます。 一般的には名前、式、または型です。

注: 例えば、vec3<f32>はテンプレートパラメータ化で、vec3が修飾される一般概念、 <f32>がテンプレートリスト(パラメータはf32型)。 vec3<f32>は具体的なベクトル型を表します。

注: 例えば、var<storage,read_write>は一般的なvar概念を、テンプレートパラメータstorageread_writeで修飾します。

注:例えば、array<vec4<f32>>は2つのテンプレートパラメータ化を持ちます:

テンプレートリストを区切る'<'(U+003C)と'>'(U+003E)コードポイントは、以下の場合にも使われます:

構文上の曖昧さはテンプレートリストを優先して解決されます:

テンプレートリスト発見アルゴリズムは下記。 以下の前提・性質を使います:

  1. テンプレートパラメータであり、'<'(U+003C)や'='(U+003D)で始まらない。

  2. 式は';'(U+003B)、'{'(U+007B)、':'(U+003A)を含まない。

  3. 式には代入文は含まれない。

  4. '='(U+003D)が現れるのは比較演算( '<=', '>=', '==', '!=' )の場合のみ。他は代入の一部。

  5. テンプレートリスト区切りは括弧'(...)'や配列インデックス'[...]'による入れ子式に従い、開始・終了は同じ入れ子レベルで現れる。

アルゴリズム: テンプレートリスト発見

入力: プログラムのソーステキスト。

レコード型:

UnclosedCandidateは以下を含むレコード型:

TemplateListは以下を含むレコード型:

出力: DiscoveredTemplateListsTemplateListレコードのリスト)

手順:

注:このアルゴリズムは、テンプレートパラメータのソース範囲を見つけるように修正できます:

注: アルゴリズムはリテラルを明示的にスキップします。なぜなら数値リテラルの末尾に文字が来る場合があり、例えば1.0fの末尾fident_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<<CB+左シフト演算子'<<'Cです。 テンプレート発見アルゴリズムはB→'<'(U+003C)と見て、次も'<'(U+003C)なのでテンプレート引数開始とせず、 B直後の'<'はテンプレートリスト開始ではありません。 最初の'<'と最後の'>'のみがテンプレートリスト区切りで、パラメータはB<<Cです。

注: A<B<=C>も同様に、B<=CB+小なりイコール演算子'<='Cです。 テンプレート発見アルゴリズムはB'<'(U+003C)→'='(U+003D)と見て、'='はテンプレート引数開始にならないので、B直後の'<'はテンプレートリスト開始ではありません。 最初の'<'と最後の'>'のみがテンプレートリスト区切りで、パラメータはB<=Cです。

注: A<(B>=C)>では、最初の'<'(U+003C)から最後の'>'(U+003E)までがテンプレートリストで、引数はB>=Cです。 B後の'>'(U+003C)コードポイント(誤記?)の後、'='(U+003D)は代入と誤認しないよう特別扱いします。

注: A<(B!=C)>では、最初の'<'(U+003C)から最後の'>'(U+003E)までがテンプレートリストで、引数はB!=Cです。 B後の'!'(U+0021)コードポイントの後、'='(U+003D)は代入と誤認しないよう特別扱いします。

注: A<(B==C)>では、最初の'<'(U+003C)から最後の'>'(U+003E)までがテンプレートリストで、引数はB==Cです。 B後の最初の'='(U+003D)コードポイント、次の'='(U+003D)コードポイントもどちらも代入と誤認しないよう特別扱いします。

テンプレートリスト発見完了後、 構文解析は各テンプレートリストをtemplate_list構文規則にマッチさせます。

template_list :

_template_args_start template_arg_comma_list _template_args_end

template_arg_comma_list :

template_arg_expression ( ',' template_arg_expression ) * ',' ?

template_arg_expression :

expression

4. ディレクティブ

ディレクティブは、WGSLプログラムの処理方法をWebGPU実装に変更させるトークン列です。

ディレクティブは省略可能です。 指定されている場合は、すべてのディレクティブが宣言constアサーションよりも前に現れる必要があります

global_directive

diagnostic_directive

| enable_directive

| requires_directive

4.1. 拡張

WGSLは今後も進化することが期待されています。

拡張は、WGSL仕様の一貫性のある変更をまとめた名前付きグループであり、以下の任意の組み合わせで構成されます:

仮に拡張は以下のようなことが可能です:

拡張には2種類あります:有効化拡張言語拡張です。

4.1.1. 有効化拡張

有効化拡張は、以下の条件を満たす場合のみ利用可能な拡張です:

有効化拡張は、ハードウェア固有の機能を公開するために意図されています。

enableディレクティブは、ひとつ以上の有効化拡張を有効にするディレクティブです。 実装が全ての指定された有効化拡張をサポートしていない場合、シェーダー生成エラーとなります。

enable_directive

'enable' enable_extension_list ';'

enable_extension_list

enable_extension_name ( ',' enable_extension_name ) * ',' ?

他のディレクティブ同様、enableディレクティブが存在する場合は、すべての宣言constアサーションよりも前に現れる必要があります。 拡張名は識別子ではありません。 宣言に解決されません。

有効な有効化拡張は次の表に示されています。

有効化拡張
WGSL有効化拡張 WebGPU GPUFeatureName 説明
f16 "shader-f16" f16型がWGSLモジュールで利用可能になります。それ以外の場合、f16(直接または間接的に)を使用するとシェーダー生成エラーとなります。
clip_distances "clip-distances" 組み込み変数clip_distancesがWGSLモジュールで利用可能になります。それ以外の場合、clip_distancesを使用するとシェーダー生成エラーとなります。
dual_source_blending "dual-source-blending" 属性blend_srcがWGSLモジュールで利用可能になります。それ以外の場合、blend_srcを使用するとシェーダー生成エラーとなります。
subgroups "subgroups" サブグループ組み込み変数サブグループ組み込み関数quad組み込み関数をWGSLモジュールで利用可能です。 それ以外の場合、いずれかを使用するとシェーダー生成エラーとなります。
primitive_index "primitive-index" 組み込み変数primitive_indexがWGSLモジュールで利用可能になります。それ以外の場合、primitive_indexを使用するとシェーダー生成エラーとなります。
例:仮想有効化拡張の利用
// 任意精度浮動小数点型の仮想拡張を有効化
enable arbitrary_precision_float;
enable arbitrary_precision_float; // 冗長なenableディレクティブも許容されます。

// 丸めモード制御用の仮想拡張を有効化
enable rounding_mode;

// 仮にarbitrary_precision_float拡張により以下が利用可能になる:
//    - 型f<E,M>
//    - 関数の戻り値、仮引数、let宣言の型として
//    - AbstractFloatからの値コンストラクター
//    - 除算演算子: / のオペランドとして
// 仮にrounding_mode拡張で@rounding_mode属性が利用可能になる。
@rounding_mode(round_to_even)
fn halve_it(x : f<8, 7>) -> f<8, 7> {
  let two = f<8, 7>(2);
  return x / 2; // 偶数丸めモードで演算される。
}

4.1.2. 言語拡張

言語拡張 は、実装がサポートしている場合に自動的に利用可能となる拡張です。 プログラムが明示的に要求する必要はありません。

言語拡張 は、あらゆるWebGPU実装で合理的にサポート可能な機能を具現化しています。 この機能が普遍的に利用できない場合、それは一部のWebGPU実装がまだ対応していないためです。

注: 例えば、do-whileループは言語拡張となり得ます。

wgslLanguageFeatures メンバーはWebGPU GPU オブジェクトにおいて、 実装がサポートする言語拡張のセットを一覧します。

requiresディレクティブ は、プログラムが利用する言語拡張記述するディレクティブです。 実装が提供する機能を変更するものではありません。 実装が必要とされる拡張のいずれかをサポートしていない場合、シェーダー生成エラーとなります。

WGSLモジュールはrequiresディレクティブを使って、非移植性の可能性や、 意図した移植性の最低限の基準を示すことができます

注: WebGPU実装外のツールは、プログラムで利用されるすべての言語拡張がプログラム内のrequiresディレクティブで網羅されているか確認できます。

requires_directive

'requires' language_extension_list ';'

language_extension_list

language_extension_name ( ',' language_extension_name ) * ',' ?

他のディレクティブ同様、requiresディレクティブが存在する場合は、すべての宣言constアサーションよりも前に現れる必要があります。 拡張名は識別子ではありません。 宣言に解決されません。

言語拡張
WGSL言語拡張 説明
readonly_and_readwrite_storage_textures read およびread_writeアクセスモードstorage textureで利用可能になります。 また、textureBarrier組み込み関数が追加されます。
packed_4x8_integer_dot_product 4要素8ビット整数ベクトルを32ビット整数スカラーにパックして、dot4U8Packedおよび dot4I8Packed組み込み関数でドット積命令の入力として利用可能です。 さらに、pack4xI8pack4xU8pack4xI8Clamppack4xU8Clampunpack4xI8unpack4xU8組み込み関数によるパック・アンパック命令が追加されます。
unrestricted_pointer_parameters 制限のうち、ユーザー定義関数に関する以下を削除します:

ユーザー定義関数において、ポインター型パラメータは 以下のいずれかのアドレス空間でなければなりません

ユーザー定義関数のポインター型引数は、 そのroot identifierと 同じmemory view でなければなりません

pointer_composite_access ルート式がポインターの場合に複合値分解式をサポートし、 参照(reference)を生成します。

例えば、pがメンバーmを持つ構造体へのポインターの場合、p.mpが指す構造体内のmのメモリ位置への参照となります。

同様に、paが配列へのポインターの場合、pa[i]paが指す配列のi番目の要素のメモリ位置への参照となります。

注: 将来的には、WGSLは現時点で広くサポートされている言語拡張の機能すべてを含める言語拡張を定義する意図があります。 requiresディレクティブにおいて、これらは全ての共通機能をリストアップするための略記となります。 機能の集合は徐々に増加し、ある種の言語バージョンと考えることもできます。

4.2. グローバル診断フィルター

グローバル診断フィルターは、影響範囲がWGSLモジュール全体となる診断フィルターです。 これはディレクティブであり、すべてのモジュールスコープ宣言よりも前に現れます。 属性形式と同じスペルですが、先頭の@(U+0040)コードポイントがなく、末尾にセミコロンが付きます。

diagnostic_directive

'diagnostic' diagnostic_control ';'

5. 宣言とスコープ

宣言は、識別子を 以下のいずれかのオブジェクト種別と関連付けます:

言い換えれば、宣言はオブジェクトの名前を導入します。

宣言がプログラムソース内で他の宣言の本文外に現れる場合、その宣言はモジュールスコープです。

関数宣言はモジュールスコープで現れます。 関数宣言は仮引数の宣言を含み、変数や値の宣言本文内に含むこともできます。 これらの内包宣言はモジュールスコープではありません。

注: 他の宣言を内包できる唯一の宣言は関数宣言です。

一部のオブジェクトはWebGPU実装により提供され、WGSLモジュールソースの開始前に宣言されたものとして扱われます。 これらのオブジェクトは事前宣言されているといいます。 例えば、WGSLは以下を事前宣言します:

スコープは、宣言された識別子が関連するオブジェクトを 示す可能性があるプログラムソースの位置集合です。 その識別子は、その宣言のスコープ内にあるといいます。

宣言の現れる位置によってスコープが決まります:

同じWGSLソースプログラム内で、2つの宣言が同時に:

注: 事前宣言オブジェクトはWGSLソース内に宣言がありません。 したがって、ユーザーが指定した宣言がモジュールスコープや関数内にあっても、事前宣言オブジェクトと同じ名前を持つことができます。

識別子は文法的コンテキストによって以下のように使われます:

identトークンが他の場所で宣言されたオブジェクトを示す名前として現れる場合、 それは何らかの宣言のスコープ内である必要があります。 識別子トークンが示すオブジェクトは次のように決定されます:

上記アルゴリズムで識別子を宣言に対応付ける場合、その識別子がその宣言に解決するといいます。 同様に、その識別子が宣言されたオブジェクトに解決するといいます。

いずれかのモジュールスコープ宣言が再帰的である場合はシェーダー生成エラーです。 すなわち、宣言間にサイクルが存在してはなりません:

次の有向グラフを考えます:

このグラフにサイクルがあってはなりません。

注: 関数本文関数宣言の一部なので、 関数も直接・間接のいずれも再帰的であってはなりません。

注:モジュールスコープ識別子宣言は利用より前に現れる必要があります。

例:有効・無効な宣言
// 有効:ユーザー定義変数は組み込み関数と同じ名前を持てる。
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では以下の異なる値に対応します:

WGSLはこれらを区別します。なぜなら機械表現や操作が異なるためです。

型は事前宣言されているか、WGSLソース内で宣言によって作成されます。

一部の型はテンプレートパラメータ化で表現されます。 型ジェネレーターとは、事前宣言されたオブジェクトで、テンプレートリストでパラメータ化されることで型を示します。 例えば、型atomic<u32>は型ジェネレーターatomicとテンプレートリスト<u32>を組み合わせたものです。

型の概念とWGSLでその型を示す構文は区別されます。 多くの場合、この仕様における型の綴りはWGSL構文と同じです。 例えば:

一部のWGSL型は、ソースプログラムの解析や実行時挙動の決定にのみ使われます。 この仕様ではそのような型も説明しますが、WGSLソーステキストには現れません。

注: 参照型はWGSLモジュールに記述されません。§ 6.4.3 参照型とポインター型を参照してください。

6.1. 型検査

WGSL値は式の評価によって算出されます。 とは、WGSL文法規則のうち「expression」で終わる名前を持つものとして解析されるソーステキストの区間です。 式Eは、外側の式Eに真に内包された式である部分式を含むことがあります。 トップレベル式は、それ自身が部分式でない式です。 § 8.18 式文法のまとめを参照。

式の評価で生成される値は次に依存します:

特定の式を評価した結果得られる値は必ず特定のWGSL型に属します。 これはその式の静的型と呼ばれます。 WGSLの規則は、式の静的型がその式の静的コンテキストのみに依存するよう設計されています。

型アサーションは、WGSLソース式とWGSL型の対応付けです。 次の記法

e : T

は「eの静的型がTである」という型アサーションです。

注: 型アサーションはプログラムテキストについての事実の記述です。実行時検査ではありません。

文はしばしば式を用い、その式の静的型に要件を課す場合があります。例:

型検査とは、正しく構文解析されたWGSLモジュールに対して、 各式を静的型に対応付け、各文の型要件が満たされていることを検証する過程です。 型検査に失敗すると、シェーダー生成エラーの一種である型エラーとなります。

型検査は、型規則を構文的フレーズに再帰的に適用することによって行えます。 構文的フレーズは、またはです。 型規則は、 構文的フレーズの静的コンテキストが、 その句に含まれる式の静的型をどのように決定するかを記述します。 型規則は2つの部分を持ちます:

型規則は、前提条件や結論に型パラメータを持つことがあります。 型規則の結論や前提条件に型パラメータが含まれる場合、その規則はパラメータ化されているといいます。 含まれない場合は完全展開されているといいます。 パラメータ化された型規則に対し、各型パラメータに型を代入することで完全展開された型規則を作ることができます。 規則の型パラメータへの型の割り当てを代入と呼びます。

例えば、論理否定!e形式の式)の型規則は次のとおりです:

前提条件 結論
e: T
TはboolまたはvecN<bool>
!e: T

これは型パラメータTを含むためパラメータ化された規則です。 Tは4つの型、boolvec2<bool>vec3<bool>vec4<bool>のいずれかになり得ます。 例えばTvec3<bool>を割り当てると、完全展開された型規則は次のようになります:

前提条件 結論
e: vec3<bool>
!e: vec3<bool>

パラメータ化された規則に対し、条件を満たす代入によって得られる完全展開規則をそれぞれオーバーロードと呼びます。 例えば、この論理否定規則は型パラメータTの割り当て方法が4通りなので、オーバーロードは4つあります。

注: つまり、パラメータ化された型規則は、異なる代入によって生成される完全展開型規則の集合のパターンを提供します。

型規則が構文的フレーズに適用されるのは、次の場合です:

パラメータ化された型規則は、ある式に対し、 代入によって完全展開型規則を生成でき、 その型規則がその式に適用できる場合に適用されます。

例えば、式1u+2uを考えます。 これは2つのリテラル部分式1u2u、どちらもu32型)を持ちます。 トップレベル式は加算です。 § 8.7 算術式の規則を参照すると、加算の型規則がこの式に適用されます。なぜなら:

構文的フレーズを解析する際、以下の3つの場合があります:

上記の例の通り、式1u+2uには型規則が一つだけ適用できるため、型検査はその型規則の結論(1u+2uがu32型)を受け入れます。

WGSLソースプログラムが型安全であるとは、次のときです:

そうでない場合は型エラーとなり、そのソースプログラムはWGSLモジュールとして有効ではありません。

WGSLは静的型付け言語です。 なぜならWGSLモジュールの型検査は、プログラムソーステキストのみを調べて成功するか型エラーを発見するからです。

6.1.1. 型規則表

WGSLの式の型規則は、型規則表として整理されており、各行が1つの型規則を表します。

式の意味は、その式を評価したときの効果であり、主に結果値の生成です。 式に適用される型規則の説明列には、その式の意味が記載されます。 意味は通常、型規則パラメータの値や、部分式の想定値に依存します。 場合により、式の意味には結果値以外の効果(部分式の副作用など)が含まれることもあります。

例:式の副作用
fn foo(p : ptr<function, i32>) -> i32 {
  let x = *p;
  *p += 1;
  return x;
}

fn bar() {
  var a: i32;
  let x = foo(&a); // fooの呼び出しは値を返し、
                   // aの値を更新する
}

6.1.2. 変換ランク

型アサーションe:T型規則の前提条件として使われる場合、次で満たされます:

この規則は、下表で定義される型の組に対するConversionRank関数で定式化されます。 ConversionRank関数は、一方の型(Src)からもう一方の型(Dest)への自動変換の優先度と実現可能性を表します。 ランクが低いほど望ましいです。

実現可能な自動変換は、型Srcから型Destへの値変換であり、 ConversionRank(Src,Dest)が有限の場合に許可されます。 これらの変換は値を保全しますが、詳細は§ 15.7 浮動小数点評価で説明される制限があります。

注: 自動変換は2つの場合のみ発生します。 1つ目は定数式をGPUで利用できる型付き数値値に変換する場合。 2つ目はメモリ参照からロードが発生し、そのメモリに格納された値が得られる場合です。

注: ランクが無限大の変換は実現不可能、つまり許可されません。

注: 変換を行わない場合、変換ランクは0です。

型間のConversionRank
Src Dest ConversionRank(Src,Dest) 説明
T T 0 同一。変換は行わない。
ref<AS,T,AM>
アドレス空間 ASアクセスモード AMreadまたはread_writeの場合)
T 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 AbstractIntAbstractFloat、その後AbstractFloat→f32と同じ挙動
AbstractInt f16 7 AbstractIntAbstractFloat、その後AbstractFloat→f16と同じ挙動
vecN<S> vecN<T> ConversionRank(S,T) 要素型の変換ランクを継承
matCxR<S> matCxR<T> ConversionRank(S,T) 要素型の変換ランクを継承
array<S,N> array<T,N> ConversionRank(S,T) 要素型の変換ランクを継承 注:固定長配列のみ抽象型要素を持てます。
__frexp_result_abstract __frexp_result_f32 1
__frexp_result_abstract __frexp_result_f16 2
__frexp_result_vecN_abstract __frexp_result_vecN_f32 1
__frexp_result_vecN_abstract __frexp_result_vecN_f16 2
__modf_result_abstract __modf_result_f32 1
__modf_result_abstract __modf_result_f16 2
__modf_result_vecN_abstract __modf_result_vecN_f32 1
__modf_result_vecN_abstract __modf_result_vecN_f16 2
S T
(上記に該当しない場合)
infinity 他の型間で自動変換はありません。

Tは型S具象化であるのは、次の場合です:

Tの値e具象化は、 TからTの具象化への実現可能な変換をeに適用した結果です。

注: f32への変換は常にf16より優先されるため、 自動変換でf16が生成されるのは、 モジュールでf16拡張が有効な場合のみです。

6.1.3. オーバーロード解決

複数の型規則が構文的フレーズに適用できる場合、 どれを適用するかを決定するための競合解決手順が用いられます。 この手順をオーバーロード解決と呼びます。 型検査によって部分式の静的型がすでに決定されていることを前提とします。

構文的フレーズPと、Pに適用できるすべての型規則を考えます。 オーバーロード解決アルゴリズムはこれらの型規則をオーバーロード候補と呼びます。 各候補について:

Pのオーバーロード解決は以下の手順で進み、最も望ましいオーバーロード候補を1つ見つけることを目的とします:

  1. 各候補Cについて、構文的フレーズ内の部分式ごとに変換ランクを列挙します。 候補の前提条件は満たされているため、P内のi番目の部分式について:

    • その静的型は計算済み。

    • その式の静的型から前提条件の型アサーションが要求する型への実現可能な自動変換が存在する。 C.R(i)をその変換のConversionRankとする。

  2. 部分式のいずれかが自動変換後に抽象型になるが、 その候補の他の部分式が定数式でない場合、その候補を除外する。

    注: 結果として、フレーズ内のいずれかの部分式が定数式でない場合、フレーズ内のすべての部分式は具象型でなければなりません。

  3. 候補を順位付けする:2つのオーバーロード候補C1C2について、C1優先されるのは:

    • P内の各式位置iについて、C1.R(i) ≤ C2.R(i)

      • つまり、C1Pに適用するために必要な各式変換が、C2に必要な対応する式変換と同等以上に望ましい。

    • 少なくとも1つの式位置iで、C1.R(i) < C2.R(i)

      • つまり、C1に必要な式変換のうち少なくとも1つは、C2に必要な対応する変換よりも厳密に望ましい。

  4. 他のすべてより優先される候補Cが1つだけあれば、オーバーロード解決は成功し、その型規則Cを返す。 そうでなければ、オーバーロード解決は失敗する。

6.2. プレーン型

プレーン型は、ブール値、数値、ベクトル、行列、またはそれらの値の集約の機械表現用の型です。

プレーン型は、スカラー型、アトミック型、 または合成型のいずれかです。

注: WGSLのプレーン型はC++のPlain-Old-Data型に似ていますが、 アトミック型や抽象数値型も含みます。

6.2.1. 抽象数値型

これらの型はWGSLソースで記述できません。型検査のみに使われます。

特定の式はシェーダー生成時に評価され、 GPUで直接実装される範囲や精度より大きい数値範囲・精度で評価される場合があります。

WGSLはこれらの評価のために、2つの抽象数値型を定義します:

これらの型で式を評価する場合、オーバーフローや無限大・NaN値を生成してはなりません

型は、抽象数値型であるか抽象数値型を含んでいれば抽象型です。 そうでなければ具象型です。

サフィックスのない数値リテラルは、抽象数値型の値を表します:

例:式log2(32)の解析:

例:式1 + 2.5の解析:

例:let x = 1 + 2.5;

例:1u + 2.5シェーダー生成エラーとなります:

例:-1 * i32(-2147483648)シェーダー生成エラーになりません:

例:リテラルの型推論
// 明示型付き符号なし整数リテラル
var u32_1 = 1u; // u32を保持

// 明示型付き符号付き整数リテラル
var i32_1 = 1i; // i32を保持

// 明示型付き浮動小数点リテラル
var f32_1 = 1f; // f32を保持

// 明示型付き符号なし整数リテラルは負にできない
var u32_neg = -1u; // 無効:u32は単項マイナス非対応

// 具象型が必要だが文や式のどの部分も型を強制しない場合、整数リテラルはi32として解釈される:
//   let宣言の初期化式は構築可能型(またはポインター)でなければならない。
//   AbstractInt→構築可能型の自動変換で最優先(変換ランク2)はAbstractInt→i32。よって'1'はi32型になる。
let some_i32 = 1; // 例:let some_i32: i32 = 1i;

// 宣言型から推論
var i32_from_type : i32 = 1; // i32を保持。AbstractInt→i32、変換ランク2
var u32_from_type : u32 = 1; // u32を保持。AbstractInt→u32、変換ランク3

// サフィックス無し整数リテラルは必要なら浮動小数点に変換可能:
//   AbstractInt→f32で自動変換、変換ランク5。
var f32_promotion : f32 = 1; // f32を保持

// 無効:浮動小数点→整数への実現可能な変換はない
var i32_demotion : i32 = 1.0; // 無効

// 式から推論
var u32_from_expr = 1 + u32_1; // u32を保持
var i32_from_expr = 1 + i32_1; // i32を保持

// 値は表現可能でなければならない
let u32_too_large   : u32 = 1234567890123456890; // 無効、オーバーフロー
let i32_too_large   : i32 = 1234567890123456890; // 無効、オーバーフロー
let u32_large : u32 = 2147483649; // 有効
let i32_large : i32 = 2147483649; // 無効、オーバーフロー
let f32_out_of_range1 = 0x1p500; // 無効、範囲外
let f32_hex_lost_bits = 0x1.0000000001p0; // 無効、f32で正確に表現できない

// 最小整数:AbstractIntに単項否定、型はi32に推論
// AbstractInt→構築可能型への最優先自動変換(最小変換ランク)はAbstractInt→i32
let i32_min = -2147483648;  // 型はi32

// 無効。AbstractInt→i32で型推論するが値が範囲外でシェーダー生成エラー
let i32_too_large_2 = 2147483648; // 無効

// 部分式はAbstractIntやAbstractFloatに解決可能。
// 次の例はすべて有効で変数値は6u。
var u32_expr1 = (1 + (1 + (1 + (1 + 1)))) + 1u;
var u32_expr2 = 1u + (1 + (1 + (1 + (1 + 1))));
var u32_expr3 = (1 + (1 + (1 + (1u + 1)))) + 1;
var u32_expr4 = 1 + (1 + (1 + (1 + (1u + 1))));

// 組み込み関数パラメータによる型推論

// 最優先候補はclamp(i32,i32,i32)->i32
let i32_clamp = clamp(1, -5, 5);
// 最優先候補はclamp(u32,u32,u32)。リテラルはAbstractInt→u32へ自動変換
let u32_clamp = clamp(5, 0, u32_from_expr);
// 最優先候補はclamp(f32,f32,f32)->f32。リテラルはAbstractInt→f32へ自動変換
let f32_clamp = clamp(0, f32_1, 1);

// 次の例はすべてf32に昇格し、初期値は10f
let f32_promotion1 = 1.0 + 2 + 3 + 4;
let f32_promotion2 = 2 + 1.0 + 3 + 4;
let f32_promotion3 = 1f + ((2 + 3) + 4);
let f32_promotion4 = ((2 + (3 + 1f)) + 4);

// 型規則違反
// 無効:初期化子はf32にしか解決できない
// AbstractFloat→u32への自動変換は不可
let mismatch : u32 = 1.0;

// 無効:clampは符号混在引数のオーバーロードがない
let ambiguous_clamp = clamp(1u, 0, 1i);

// 推論は文レベルで完了
// let宣言の初期化式は構築可能型(またはポインター)でなければならない。
// AbstractInt→構築可能型への最優先自動変換(最小変換ランク)はAbstractInt→i32。よって'1'はi32型になる。
let some_i32 = 1; // 例:let some_i32: i32 = 1i;

let some_f32 : f32 = some_i32; // 型エラー:i32はf32に代入不可

// もう1つのオーバーフロー例
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型はtruefalseの値を持ちます。

ブールリテラル型規則
前提条件 結論 説明
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ビット浮動小数点値の集合です。シェーダー生成エラー となるのは、プログラムに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. スカラー型

スカラー型は、boolAbstractIntAbstractFloati32u32f32f16です。

数値スカラー型は、AbstractIntAbstractFloati32u32f32f16です。

整数スカラー型は、AbstractInti32u32です。

スカラー変換は、あるスカラー型の値を別のスカラー型の値へ写像します。 一般に、変換後の値は変換前の値に近く、変換先型の制限内で表現されます。 スカラー変換は次の場合に発生します:

6.2.6. ベクトル型

ベクトルは2, 3, 4個のスカラー 要素をまとめたものです。

説明
vecN<T> T型の要素をN個持つベクトル。 Nは{2, 3, 4}のいずれかであり、T必ずスカラー型でなければなりません。 Tはベクトルの要素型です。

ベクトルの要素型が数値スカラーであれば、そのベクトルは数値ベクトルです。

ベクトルの主な利用例:

ベクトル(および行列)に対する多くの操作は 要素ごとに行われます。つまり、各スカラー要素ごとに独立して操作します。

例:ベクトル
vec2<f32>  // 2つのf32からなるベクトル
例:要素ごとの加算
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]

WGSLはまた、次の事前宣言型エイリアスを宣言します:

事前宣言エイリアス 元型 制限
vec2i vec2<i32>
vec3i vec3<i32>
vec4i vec4<i32>
vec2u vec2<u32>
vec3u vec3<u32>
vec4u vec4<u32>
vec2f vec2<f32>
vec3f vec3<f32>
vec4f vec4<f32>
vec2h vec2<f16> f16拡張が必要。
vec3h vec3<f16>
vec4h vec4<f16>

6.2.7. 行列型

行列は2, 3, 4個の浮動小数点ベクトルをまとめたものです。

説明
matCxR<T> C列×R行、型Tの行列。C, Rは{2, 3, 4}のいずれかで、Tf32f16AbstractFloatのいずれかでなければなりません。 同等に、C個のvecR<T>型の列ベクトルと考えることもできます。

行列の主な用途は線形変換の表現です。 この解釈では、行列のベクトルは列ベクトルとして扱われます。

乗算演算子(*)は以下の用途で使われます:

§ 8.7 算術式を参照してください。

例:行列
mat2x3<f32>  // 2列3行の32ビット浮動小数点行列
             // 同等に、2つのvec3<f32>型の列ベクトル

WGSLはまた、以下の事前宣言型エイリアスも宣言します:

事前宣言エイリアス 元型 制限
mat2x2f mat2x2<f32>
mat2x3f mat2x3<f32>
mat2x4f mat2x4<f32>
mat3x2f mat3x2<f32>
mat3x3f mat3x3<f32>
mat3x4f mat3x4<f32>
mat4x2f mat4x2<f32>
mat4x3f mat4x3<f32>
mat4x4f mat4x4<f32>
mat2x2h mat2x2<f16> f16拡張が必要。
mat2x3h mat2x3<f16>
mat2x4h mat2x4<f16>
mat3x2h mat3x2<f16>
mat3x3h mat3x3<f16>
mat3x4h mat3x4<f16>
mat4x2h mat4x2<f16>
mat4x3h mat4x3<f16>
mat4x4h mat4x4<f16>

6.2.8. アトミック型

アトミック型は、 具象整数スカラー型をカプセル化し、以下の特徴を持ちます:

説明
atomic<T> Tのアトミック。T必ずu32またはi32でなければなりません。

式がアトミック型に評価されてはなりません

アトミック型は、workgroup アドレス空間の変数、またはstorage buffer変数(read_writeアクセスモード)でのみインスタンス化可能です。 型への操作のメモリスコープは、その型がインスタンス化されるアドレス空間で決まります。 workgroup空間のアトミック型はWorkgroupスコープ、 storage空間のアトミック型はQueueFamilyスコープです。

アトミック変更とは、 アトミックオブジェクトに対して値を書き換える操作のことです。 新しい値が既存値と同じ場合でも「変更」とみなします。

WGSLでは、アトミック変更は各オブジェクトごとに相互順序付けされます。 つまり、シェーダーステージの実行中、アトミックオブジェクトAごとに、 すべてのエージェントがAに適用された変更操作の順序を同じように観測します。 別個のアトミックオブジェクト間の順序は関連付けられません。因果関係も暗示されません。 workgroup空間の変数は同一workgroup内で共有されますが、 異なるworkgroup間では共有されません。

6.2.9. 配列型

配列は要素値をインデックスでアクセスできる並びです。

説明
array<E,N> 固定長配列E型の要素をN個持つ。
Nは配列の要素数です。
array<E> 実行時サイズ配列E型の要素からなる配列。 特定の文脈でのみ現れます。

配列の最初の要素はインデックス0、以降は整数インデックスでアクセスします。 § 8.5.3 配列アクセス式参照。

式が実行時サイズ配列型に評価されてはなりません

固定長配列の要素数式Nには以下の制約があります:

注: 要素数値がoverride宣言に依存する場合はパイプライン生成時、 それ以外はシェーダーモジュール生成時に完全に決まります。

注: 型等価性判定のため、定数式でないoverride式は識別子でなければなりません。 オーバーライド可能定数でサイズ指定したworkgroup変数例参照。

実行時サイズ配列の要素数は、対応するstorage buffer変数に関連付けられたバッファバインディングのサイズで決まります。 § 13.3.4 バッファバインディングによる実行時サイズ配列の要素数決定参照。

配列要素型は、以下のいずれかでなければなりません

注: 要素型はプレーン型でなければなりません。

2つの配列型が同じかどうかは、以下すべてが満たされた場合のみです:

例:固定長配列型(オーバーライド不可の要素数)
// array<f32,8>とarray<i32,8>は型が異なる:要素型が違う
var<private> a: array<f32,8>;
var<private> b: array<i32,8>;
var<private> c: array<i32,8u>;  // array<i32,8>とarray<i32,8u>は同じ型

const width = 8;
const height = 8;

// array<i32,8>、array<i32,8u>、array<i32,width>は同じ型。要素数評価は8
var<private> d: array<i32,width>;

// array<i32,height>とarray<i32,width>は同じ型
var<private> e: array<i32,width>;
var<private> f: array<i32,height>;

注: オーバーライド可能定数でサイズ指定した配列型の有効な利用は、 workgroupアドレス空間でのメモリビューとしてのみです。 これはworkgroup変数の格納型を含みます。 § 7 変数と値の宣言参照。

例:オーバーライド可能定数でサイズ指定したworkgroup変数
override blockSize = 16;

var<workgroup> odds: array<i32,blockSize>;
var<workgroup> evens: array<i32,blockSize>; // 同じ型

// 以下はすべて'odds'および'evens'と型が異なる
// 違う型:識別子'blockSize'でない
var<workgroup> evens_0: array<i32,16>;
// 違う型:算術式で要素数指定
var<workgroup> evens_1: array<i32,(blockSize * 2 / 2)>;
// 違う型:括弧付き識別子
var<workgroup> evens_2: array<i32,(blockSize)>;

// 無効例:オーバーライド要素数は最外部のみ
// var<workgroup> both: array<array<i32,blockSize>,2>;

// 無効例:オーバーライド要素数はworkgroup変数でのみ有効
// var<private> bad_address_space: array<i32,blockSize>;

6.2.10. 構造体型

構造体は、名前付きメンバー値を名前付きでまとめたものです。

説明
struct AStructName {
M1 : T1,
...
MN : TN,
}
識別子AStructNameで名前付けされた構造体型の宣言で、 N個のメンバーを持ちます。 メンバーiは識別子Miで名前付けされ、 型はTiです。

N必ず1以上でなければなりません。

同じ構造体型内の2つのメンバーは同じ名前であってはなりません

構造体型はモジュールスコープで宣言されます。 プログラムソースの他の場所では、構造体型はその識別子名で示されます。 § 5 宣言とスコープ参照。

2つの構造体型は名前が同じ場合のみ同じ型です。

構造体メンバー型は、以下のいずれかでなければなりません

注: ユーザー宣言構造体型はすべて具象型です。

注: 各メンバー型はプレーン型でなければなりません。

構造体メンバー型および配列要素型の制約により生じる結果:

例:構造体
// 3つのメンバーを持つ構造体
struct Data {
  a: i32,
  b: vec2<f32>,
  c: array<i32,10>, // 最後のカンマは省略可能
}

// Data型値を格納する変数を宣言
var<private> some_data: Data;
struct_decl

'struct' ident struct_body_decl

struct_body_decl

'{' struct_member ( ',' struct_member ) * ',' ? '}'

struct_member

attribute * member_ident ':' type_specifier

構造体メンバーに適用できる属性:

属性builtinlocationblend_srcinterpolateinvariantIO属性です。 構造体SのメンバーにIO属性がある場合、S仮引数戻り値型としてエントリーポイントで使われる場合のみ効果があります。 § 13.3.1 ステージ間入出力インターフェース参照。

属性alignsizeレイアウト属性であり、 構造体型がユニフォームバッファストレージバッファを定義する際に必要となる場合があります。 § 14.4 メモリレイアウト参照。

例:構造体宣言
struct my_struct {
  a: f32,
  b: vec4<f32>
}
例:バッファ宣言に使われる構造体
// 実行時配列
alias RTArr = array<vec4<f32>>;
struct S {
  a: f32,
  b: f32,
  data: RTArr
}
@group(0) @binding(0) var<storage> buffer: S;

6.2.11. 合成型

型は、他の型を合成して内部構造を持つ場合合成型です。 内部部分は重複せず、構成要素と呼ばれます。 合成値は構成要素に分解可能です。§ 8.5 合成値分解式参照。

合成型は以下の通りです:

合成型Tについて、入れ子深度NestDepth(T))は:

6.2.12. 構築可能型

多くの種類の値は生成、ロード、格納、関数への渡し、関数からの返却が可能です。 これらを構築可能と呼びます。

型が次のいずれかであれば、構築可能です:

注: すべての構築可能型は生成時固定フットプリントを持ちます。

注: アトミック型や実行時サイズ配列型は構築可能ではありません。 アトミックや実行時サイズ配列を含む複合型も構築可能ではありません。

6.2.13. 固定フットプリント型

変数のメモリフットプリントは、その変数の内容を格納するために使われるメモリ位置の数です。 メモリフットプリントは変数の格納型に依存し、シェーダーライフサイクルのある段階で確定します。 ほとんどの変数は、シェーダー生成時にサイズが決まります。 一部の変数は、パイプライン生成時、 またはシェーダー実行開始時に決まることもあります。

型が生成時固定フットプリントを持つとは、その具象化のサイズがシェーダ生成時に完全に決定される場合を指します。

型が固定フットプリントを持つとは、そのサイズがパイプライン生成時に完全に決まる場合です。

注: すべての具象生成時固定フットプリント型・固定フットプリント型は格納可能型です。

注: パイプライン生成はシェーダー生成に依存するので、生成時固定フットプリントを持つ型は、必ず固定フットプリントも持ちます。

生成時固定フットプリントを持つ型は:

注: 構築可能型生成時固定フットプリントを持ちます。

プレーン型固定フットプリントを持つ型は:

注: 定数式でないoverride式による要素数指定の固定長配列型が有効なのは、 workgroupアドレス空間でのメモリビューのみです。 これはworkgroup変数の格納型も含みます。

注: 固定フットプリント型は直接または間接的にアトミック型を含み得ますが、構築可能型は含みません。

注: 固定フットプリント型には実行時サイズ配列、およびそれを含む構造体は含まれません。

6.3. 列挙型

列挙型は、限定された名前付き値の集合です。 列挙型は、例えば有効なテクセルフォーマットの集合など、特定の概念の可能性の集合を区別するために使われます。

列挙値は、列挙型内の名前付き値のひとつです。 各列挙値は他のすべての列挙値、および他の種類の値と区別されます。

WGSLソースで新しい列挙値や列挙型を宣言する方法はありません。

注: 列挙値はテンプレートパラメータとして使われます。

注: 列挙値をコピーしたり別名を作成する方法はありません:

6.3.1. 事前宣言列挙値

次の表はWGSLの列挙型と、その事前宣言列挙値を示します。 列挙型自体はWGSLソースで記述できません。

事前宣言列挙値
列挙型
(WGSLで記述不可)
事前宣言列挙値
アクセスモード read
write
read_write
アドレス空間

注: handleアドレス空間はWGSLソースで記述されません。

function
private
workgroup
uniform
storage
テクセルフォーマット rgba8unorm
rgba8snorm
rgba8uint
rgba8sint
rgba16unorm
rgba16snorm
rgba16uint
rgba16sint
rgba16float
rg8unorm
rg8snorm
rg8uint
rg8sint
rg16unorm
rg16snorm
rg16uint
rg16sint
rg16float
r32uint
r32sint
r32float
rg32uint
rg32sint
rg32float
rgba32uint
rgba32sint
rgba32float
bgra8unorm
r8unorm
r8snorm
r8uint
r8sint
r16unorm
r16snorm
r16uint
r16sint
r16float
rgb10a2unorm
rgb10a2uint
rg11b10ufloat

6.4. メモリビュー

WGSLプログラムはプレーン値の計算に加え、 メモリから値を読み書きすることも多く、これはメモリアクセス操作によって行われます。 各メモリアクセスはメモリビューを介して実行されます。

メモリビューは以下から構成されます:

メモリビューのアクセスモードは、アドレス空間でサポートされていなければなりません§ 7 変数と値の宣言参照。

6.4.1. 格納可能型

変数に格納される値は必ず 格納可能型でなければなりません。 格納可能型はWGSLで明示的な表現が定義されている場合もあり(§ 14.4.4 値の内部レイアウト参照)、 テクスチャやサンプラーのように不透明な場合もあります。

型が具象型で、以下のいずれかであれば格納可能型です:

注: つまり、格納可能型は具象プレーン型、テクスチャ型、サンプラー型です。

6.4.2. ホスト共有型

ホスト共有型は、ホストとGPU間で共有されるバッファの内容を記述する型や、フォーマット変換せずにホストとGPU間でコピーされる型です。 この目的で使う場合、型にはレイアウト属性が適用されることがあります(§ 14.4 メモリレイアウト参照)。 § 7.3 var宣言の通り、ユニフォームバッファストレージバッファ 変数の格納型必ずホスト共有型でなければなりません。

型が具象型で、以下のいずれかであればホスト共有型です:

注: ステージ間入出力型の制約は§ 13.3.1 ステージ間入出力インターフェースおよびそれ以降の節に記載されています。 それらの型もサイズが決まりますが、カウント方法が異なります。

注: テクスチャやサンプラーもホストとGPU間で共有できますが、その内容は不透明です。 この節のホスト共有型は、特にストレージおよびユニフォームバッファで使います。

6.4.3. 参照型とポインター型

WGSLにはメモリビューを表現する型が2種類あります: 参照型ポインター型です。

制約 説明
ASアドレス空間
T格納可能型
AMアクセスモード
ref<AS,T,AM> 参照型 であり、AS内のメモリ位置でT型の値を保持し、 AMモードによるメモリアクセスをサポートするメモリビューの集合に対応します。

ここでT格納型です。

参照型はWGSLソースでは書かれません。モジュール解析時に使われます。

ASアドレス空間
T格納可能型
AMアクセスモード
ptr<AS,T,AM> ポインター型 であり、AS内のメモリ位置でT型の値を保持し、 AMモードによるメモリアクセスをサポートするメモリビューの集合に対応します。

ここでT格納型です。

ポインター型はWGSLソースで記述可能です。

2つのポインター型は、アドレス空間・格納型・アクセスモードがすべて同じ場合のみ同じ型です。

WGSLモジュール解析時、参照型・ポインター型はアドレス空間・格納可能型・アクセスモードで完全にパラメータ化されます。 本仕様のコード例では、コメントでこの完全パラメータ化形を示します。

ただしWGSLソーステキストでは:

例:ポインター型
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に対応し、 逆も同様で、prは同じメモリビューを表します。

6.4.4. 有効・無効なメモリ参照

参照値は有効または無効です。

参照は§ 6.4.8 参照とポインター値の形成で詳しく説明されているように形成されます。 一般に、有効な参照は次の方法で形成されます:

一般に、無効なメモリ参照は次の方法で形成されます:

有効なポインター有効な参照に対応するポインターです。 無効なポインター無効なメモリ参照に対応するポインターです。

6.4.5. 起源変数

参照値R起源変数は次のように定義されます:

ポインター値の起源変数は、対応する参照値の起源変数として定義されます。

注: 起源変数は動的な概念です。 関数の仮引数の起源変数は、その関数の呼び出し元によります。 呼び出し元が異なれば、異なる起源変数へのポインターが渡されることがあります。

有効な参照は必ず、ある変数のメモリ位置の一部または全部に対応する非空のメモリビューとなります。

注: 参照は変数内部のメモリ位置に対応していても、無効であることがあります。 これは、添字が型の範囲を超えている場合などに発生し、その参照先が実際には後続の兄弟データメンバーのメモリ位置となる場合です。

次の例では、参照the_particle.position[i]は、iが0または1のときのみ有効です。 iが2の場合、その参照は無効なメモリ参照ですが、参照先はthe_particle.color_indexのメモリ位置となります。

例:変数内部でも無効なメモリ参照
struct Particle {
   position: vec2f,
   velocity: vec2f,
   color_index: i32,
}

@group(0) @binding(0)
var<storage,read_write> the_particle: Particle;

fn particle_velocity_component(p: Particle, i: i32) -> f32 {
  return the_particle.velocity[i]; // iが0または1のとき有効な参照
}

6.4.6. 範囲外アクセス

メモリアクセス操作が無効なメモリ参照をアクセスすると、範囲外アクセスとなります。

範囲外アクセスはプログラム不具合です。もしそのまま実行された場合、一般的には:

このため、実装は決してそのままアクセスを実行しません。 範囲外アクセスの実行は動的エラーとなります。

注: 格納型の誤解釈例は 前節の例で発生します。 iが2の場合、the_particle.velocity[i]式は 型ref<storage,f32,read_write>(格納型はf32)ですが、 実際のメモリ位置はcolor_indexメンバー用に割り当てられているため、値はi32型です。

注:範囲外アクセスは動的エラーを引き起こし、多様な結果があり得ます。

その結果には以下が含まれます(限定されません):

トラップ

シェーダー呼び出しは直ちに終了し、シェーダーステージ出力は0値となる。

無効ロード

無効参照からのロードは次のいずれかを返す:

無効ストア

無効参照へのストアは次のいずれか:

共有アドレス空間内の変数の別の位置へ無効なロードやストアがリダイレクトされた場合、データ競合が発生する可能性があります。 例えば、複数の並行実行呼び出しが配列の最初の要素へリダイレクトされ、少なくとも1つが書き込みなら同期されていない限りデータ競合=動的エラーとなります。

範囲外アクセスは均一性解析の前提を破棄します。 例えば、範囲外アクセスで呼び出しが早期終了すると、集合演算に参加できなくなります。 特にworkgroupBarrier呼び出しがシェーダーをハングさせたり、微分値が不正になることがあります。

6.4.7. 参照型とポインター型の利用例

参照型とポインター型は用途で区別されます:

このような参照型定義により、変数の簡便な利用が可能となります:

例:参照型による変数の簡易利用
@compute @workgroup_size(1)
fn main() {
  // 'i'はref<function,i32,read_write>型
  // 'i'のメモリ位置にはi32値0が格納されている。
  var i: i32 = 0;

  // 'i + 1'は'i'部分式がi32型でなければ型規則に一致しない。
  // よって'i + 1'式はi32型。評価時、'i'部分式はその時点でメモリ位置に格納されたi32値となる。
  let one: i32 = i + 1;

  // 'i'のメモリ位置値を2に更新
  i = one + 1;

  // 'i'のメモリ位置値を5に更新。右辺は代入前に評価される。
  i = i + 3;
}
例:参照を返す場合、参照経由でロードされた値が返る
var<private> age: i32;
fn get_age() -> i32 {
  // return文の式の型は'i32'でなければならない(関数の戻り値型に一致)。
  // 'age'式は型ref<private,i32,read_write>。
  // 参照の格納型が要求される型と一致し、他の型規則が適用されないため、Load規則を適用。
  // この文脈での'age'評価はreturn文実行時に参照するメモリ領域からロードされたi32値。
  return age;
}

fn caller() {
  age = 21;
  // copy_age定数にはi32値21が代入される。
  let copy_age: i32 = get_age();
}

ポインター型定義により、2つの主要な用途が可能となります:

例:変数内容の一部を示す短い名前としてポインターを利用
struct Particle {
  position: vec3<f32>,
  velocity: vec3<f32>
}
struct System {
  active_index: i32,
  timestep: f32,
  particles: array<Particle,100>
}
@group(0) @binding(0) var<storage,read_write> system: System;

@compute @workgroup_size(1)
fn main() {
  // ストレージメモリ内の特定Particleへのポインターを形成
  let active_particle = &system.particles[system.active_index];

  let delta_position: vec3<f32> = (*active_particle).velocity * system.timestep;
  let current_position: vec3<f32>  = (*active_particle).position;
  (*active_particle).position = delta_position + current_position;
}
例: ポインタを形式的なパラメータとして使用する
fn add_one(x: ptr<function,i32>) {
  /* 'x' の場所に次の大きい整数値を格納するように更新する、
     (もしくは、最大の負の i32 値にラップアラウンドする)。
     左辺では、単項 '*' はポインタを参照に変換し、
     それに代入できるようにする。デフォルトでは read_write アクセスモードを持つ。 
     /* 右辺について:
        - 単項 '*' はポインタを参照に変換し、read_write アクセスモードを持つ。
        - 一致する型ルールは加算 (+) のみで、'*x' が i32 型である必要がある。
          これは '*x' のストア型である。よってロードルールが適用され、
          評価時点で '*x' に格納されている値、すなわち i32 の 0 となる。
        - 0 に 1 を加算し、右辺の最終値として 1 になる。*/
     1 を '*x' のメモリに格納する。*/
  *x = *x + 1;
}

@compute @workgroup_size(1)
fn main() {
  var i: i32 = 0;

  // 'i' の内容を修正し、1 にする。
  // 単項 '&' を使い、'i' のポインタ値を取得する。
  // 呼び出し先の関数が 'i' のメモリにアクセスでき、修正可能であることを明確に示す。
  add_one(&i);
  let one: i32 = i;  // 'one' の値は 1 となる。
}

6.4.8. 参照値とポインター値の生成

参照値は次のいずれかの方法で生成されます:

全ての場合で、結果のアクセスモードは元の参照のものと同じです。

例:合成参照からの成分参照
struct S {
    age: i32,
    weight: f32
}
var<private> person: S;
// 別の場所で'person'は変数の基底メモリへの参照を表し、型はref<private,S,read_write>となる。

fn f() {
    var uv: vec2<f32>;
    // この関数本体では'uv'はその基底メモリへの参照を表し、型はref<function,vec2<f32>,read_write>となる。

    // 代入の左辺を評価:
    //   'uv.x'を評価して参照値を得る:
    //   1. まず'uv'を評価し、変数'uv'のメモリへの参照(型ref<function,vec2<f32>,read_write>)を得る。
    //   2. '.x'ベクトルアクセス句を適用し、参照値の指すベクトルの第1成分メモリへの参照(型ref<function,f32,read_write>)を得る。
    // 右辺を評価するとf32値1.0となる。1.0をuv.xのストレージメモリ位置に格納。
    uv.x = 1.0;

    // 代入の左辺を評価:
    //   'uv[1]'を評価して参照値を得る:
    //   1. まず'uv'を評価し、変数'uv'のメモリへの参照(型ref<function,vec2<f32>,read_write>)を得る。
    //   2. '[1]'配列インデックス句を適用し、参照値の指すベクトルの第2成分メモリへの参照(型ref<function,f32,read_write>)を得る。
    // 右辺はf32値2.0。2.0をuv[1]のストレージメモリ位置に格納。
    uv[1] = 2.0;

    var m: mat3x2<f32>;
    // 'm[2]'の評価:
    // 1. 'm'を評価し、変数'm'のメモリへの参照(型ref<function,mat3x2<f32>,read_write>)を得る。
    // 2. '[2]'配列インデックス句を適用し、参照値の指す行列の第3列ベクトルメモリへの参照(型ref<function,vec2<f32>,read_write>)を得る。
    // let宣言はvec2<f32>型なので、初期化子はvec2<f32>型でなければならない。
    // ロード規則が適用され、'm[2]'参照位置からロードした値が初期化子となる。
    let p_m_col2: vec2<f32> = m[2];

    var A: array<i32,5>;
    // 'A[4]'の評価:
    // 1. 'A'を評価し、変数'A'のメモリへの参照(型ref<function,array<i32,5>,read_write>)を得る。
    // 2. '[4]'配列インデックス句を適用し、参照値の指す配列の第5要素メモリへの参照(型ref<function,i32,read_write>)を得る。
    // let宣言はi32型なので、右辺はi32型でなければならない。
    // ロード規則が適用され、'A[4]'参照位置からロードした値が初期化子となる。
    let A_4_value: i32 = A[4];

    // 'person.weight'の評価:
    // 1. 'person'を評価し、モジュールスコープ変数のメモリへの参照(型ref<private,S,read_write>)を得る。
    // 2. '.weight'メンバーアクセス句を適用し、参照値の指すメモリの第2メンバー位置への参照(型ref<private,f32,read_write>)を得る。
    // let宣言はf32型なので、右辺はf32型でなければならない。
    // ロード規則が適用され、'person.weight'参照位置からロードした値が初期化子となる。
    let person_weight: f32 = person.weight;

    // また、ポインターからも同じ構文で参照値が生成できる。

    let uv_ptr = &uv;
    // この関数本体では'uv_ptr'は'uv'基底メモリへのポインターで、型はptr<function,vec2<f32>,read_write>となる。

    // 代入左辺を評価:
    //   '*uv_ptr'を評価して参照値を得る:
    //   1. 'uv_ptr'を評価し、'uv'基底メモリへのポインター(型ptr<function,vec2<f32>,read_write>)を得る。
    //   2. 間接参照演算子を適用し、'uv'のメモリへの参照を得る。
    // 右辺はvec2<f32>値(1.0, 2.0)。'uv'のストレージメモリ位置に(1.0, 2.0)を格納。
    *uv_ptr = vec2f(1.0, 2.0);

    // 代入左辺を評価:
    //   'uv_ptr.x'を評価して参照値を得る:
    //   1. 'uv_ptr'を評価し、'uv'基底メモリへのポインター(型ptr<function,vec2<f32>,read_write>)を得る。
    //   2. '.x'ベクトルアクセス句を適用し、参照値の指すベクトルの第1成分メモリへの参照(型ref<function,f32,read_write>)を得る。
    // 右辺はf32値1.0。uv.xのストレージメモリ位置に1.0を格納。
    uv_ptr.x = 1.0;

    // 代入左辺を評価:
    //   'uv_ptr[1]'を評価して参照値を得る:
    //   1. 'uv_ptr'を評価し、'uv'基底メモリへのポインター(型ptr<function,vec2<f32>,read_write>)を得る。
    //   2. '[1]'配列インデックス句を適用し、参照値の指すベクトルの第2成分メモリへの参照(型ref<function,f32,read_write>)を得る。
    // 右辺はf32値2.0。uv[1]のストレージメモリ位置に2.0を格納。
    uv_ptr[1] = 2.0;

    let m_ptr = &m;
    // 'm_ptr[2]'の評価:
    // 1. 'm_ptr'を評価し、'm'基底メモリへのポインター(型ptr<function,mat3x2<f32>,read_write>)を得る。
    // 2. '[2]'配列インデックス句を適用し、参照値の指す行列の第3列ベクトルへの参照(型ref<function,vec2<f32>,read_write>)を得る。
    // let宣言はvec2<f32>型なので、初期化子はvec2<f32>型でなければならない。
    // ロード規則が適用され、'm[2]'参照位置からロードした値が初期化子となる。
    let p_m_col2: vec2<f32> = m_ptr[2];

    let A_ptr = &A;
    // 'A[4]'の評価:
    // 1. 'A_ptr'を評価し、'A'基底メモリへのポインター(型ptr<function,array<i32,5>,read_write>)を得る。
    // 2. '[4]'配列インデックス句を適用し、参照値の指す配列の第5要素メモリへの参照(型ref<function,i32,read_write>)を得る。
    // let宣言はi32型なので、右辺はi32型でなければならない。
    // ロード規則が適用され、'A[4]'参照位置からロードした値が初期化子となる。
    let A_4_value: i32 = A_ptr[4];

    let person_ptr = &person;
    // 'person.weight'の評価:
    // 1. 'person_ptr'を評価し、モジュールスコープ変数のメモリへのポインター(型ptr<private,S,read_write>)を得る。
    // 2. '.weight'メンバーアクセス句を適用し、参照値の指すメモリの第2メンバー位置への参照(型ref<private,f32,read_write>)を得る。
    // let宣言はf32型なので、右辺はf32型でなければならない。
    // ロード規則が適用され、'person.weight'参照位置からロードした値が初期化子となる。
    let person_weight: f32 = person_ptr.weight;
}

ポインター値は次のいずれかの方法で生成されます:

全ての場合で、結果のアクセスモードは元のポインターのものと同じです。

例:変数からのポインター生成
// privateアドレス空間にf32値を格納する変数を宣言
var<private> x: f32;

fn f() {
    // functionアドレス空間にi32値を格納する変数を宣言
    var y: i32;

    // 'x'はモジュールスコープ変数'x'に解決され、型はref<private,f32,read_write>となる。
    // 単項'&'演算で参照をポインターに変換。
    // アクセスモードは元変数のものと同じ。完全型はptr<private,f32,read_write>。
    // functionアドレス空間のデフォルトアクセスモードはread_writeなので明記不要。
    let x_ptr: ptr<private,f32> = &x;

    // 'y'は関数スコープ変数'y'に解決され、型はref<private,i32,read_write>となる。
    // 単項'&'演算で参照をポインターに変換。アクセスモードはデフォルトでread_write。
    let y_ptr: ptr<function,i32> = &y;

    // 新しい変数。モジュールスコープ変数と別物。
    var x: u32;

    // ここで'x'は直前に宣言された関数スコープ変数で、型はref<function,u32,read_write>。
    // 単項'&'演算で参照をポインターに変換。アクセスモードはデフォルトでread_write。
    let inner_x_ptr: ptr<function,u32> = &x;
}

6.4.9. 他言語における参照型・ポインター型との比較

この節は参考情報であり、規範的ではありません。

WGSLの参照型・ポインター型は他言語よりも制限されています。特に:

注: 上記規則から「ダングリング」ポインター、すなわち「生存」起源変数のメモリを参照しないポインターを生成することはできません。 メモリビュー無効なメモリ参照となる場合がありますが、 決して 起源変数またはバッファに関連しないメモリ位置へアクセスしません。

6.5. テクスチャ型・サンプラー型

テクセルテクスチャの最小単位として個別にアクセス可能なスカラーまたはベクトルです。 texeltexture elementの略です。

テクスチャは、レンダリングに有用な特殊な操作をサポートするテクセル集合です。 WGSLではこれらの操作はテクスチャ組み込み関数で呼び出します。 全リストは§ 17.7 テクスチャ組み込み関数参照。

WGSLのテクスチャはWebGPUのGPUTextureに対応します。

テクスチャには以下の特徴があります:

テクセルフォーマット

各テクセルのデータ表現。§ 6.5.1 テクセルフォーマット参照。

次元性

グリッド座標の次元数と座標の解釈方法。次元数は1, 2, 3のいずれかです。 多くのテクスチャは直交座標を使います。 キューブテクスチャは6つの正方形面を持ち、三次元座標は原点からキューブ中心への方向ベクトルとして解釈されます。

WebGPUのGPUTextureViewDimension参照。

サイズ

各次元のグリッド座標の範囲。ミップレベルによって決まります。

ミップレベル数

ミップレベル数はサンプルテクスチャ深度テクスチャでは1以上、ストレージテクスチャでは1です。
ミップレベル0がテクスチャのフルサイズ版を保持し、各次レベルは前レベルをフィルタした半分サイズ(切り上げ)です。
テクスチャをサンプリングする際、明示的または暗黙的な詳細度(LOD)でミップレベルを選択し、フィルタリングで合成値を生成します。

配列化

テクスチャが配列化されているかどうか。

  • 非配列テクスチャはテクセルのグリッドです。

  • 配列化テクスチャは同種グリッドの配列です。

配列サイズ

配列化テクスチャの場合、グリッド数。

サンプル数

テクスチャがマルチサンプルの場合のサンプル数。

テクスチャ内の各テクセルには一意な論理テクセルアドレスが関連付けられており、これは整数タプルで:

テクスチャの物理的な構造は描画最適化のために設計されており、データレイアウトや型、内部処理はシェーダ言語から直接指定できません。

このため、シェーダはテクスチャ変数内のテクセルメモリに直接アクセスできません。 代わりに不透明なハンドル経由でアクセスします:

このように、テクスチャ型でサポートされる操作は、テクスチャ組み込み関数にそのテクスチャ型の仮引数が存在するかで決まります。

注: テクスチャ変数が持つハンドルはシェーダで変更できません。 すなわち、変数自体はread-onlyですが、アクセス先の基底テクスチャが可変(例:write-only ストレージテクスチャ)でも同様です。

テクスチャ型は以下の型です:

サンプラーテクセルサンプルテクスチャ深度テクスチャからアクセスする方法を制御する不透明なハンドルです。

WGSLサンプラーはWebGPUのGPUSamplerに対応します。

テクセルアクセスはサンプラーの複数のプロパティで制御されます:

アドレッシングモード

テクスチャ境界・範囲外座標の処理方法を制御。 次元ごとに独立して設定可能。 WebGPU GPUAddressMode参照。

フィルタモード

最終結果を得るためにどのテクセルを使うか制御。 最近傍テクセルまたは複数テクセル間で補間可。 複数フィルタモードは独立設定可能。 WebGPU GPUFilterMode参照。

LODクランプ

アクセスする詳細度(LOD)の最小・最大値を制御。

比較

比較サンプラー用の比較方法を制御。 WebGPU GPUCompareFunction参照。

最大異方性

サンプラーで使用する最大異方性値を制御。

サンプラーはWGSLモジュール内で生成できず、上記プロパティ等の状態はシェーダ内では不変であり、WebGPU APIのみで設定可。

フィルタリングサンプラー(補間フィルタ使用サンプラー)を非フィルタ対応フォーマットのテクスチャで使うとパイプライン生成エラーとなります。

注: サンプラー変数が持つハンドルはシェーダで変更できません。

6.5.1. テクセルフォーマット

WGSLでは、特定のテクスチャ型がテクセルフォーマットによってパラメータ化されます。

テクセルフォーマットは、次の特徴を持ちます:

チャンネル

各チャンネルはスカラー値を含みます。 テクセルフォーマットは最大4つのチャンネル(rgba)を持ち、 通常は赤・緑・青・アルファチャンネルの概念に対応します。

チャンネルフォーマット

チャンネルのビット数とそのビットの解釈方法。

WGSLの各テクセルフォーマットは、同名のWebGPU GPUTextureFormatに対応します。

WGSLソースコードで使われるのは限られたテクセルフォーマットのみです。 それらテクセルフォーマットを定義するチャンネルフォーマットは、チャンネルフォーマット表に記載されています。 最後から2番目の列は、格納ビットからシェーダ値への変換方法(チャンネル転送関数、CTF)を示します。 最後の列は、シェーダ値から格納ビットへの変換方法(逆チャンネル転送関数、ICTF)を示します。

注: 8unormのチャンネル転送関数は{0,...,255}を浮動小数点区間[0.0, 1.0]に写像します。

注: 8snormのチャンネル転送関数は{-128,...,127}を浮動小数点区間[-1.0, 1.0]に写像します。

チャンネルフォーマット
チャンネルフォーマット 格納ビット数 格納ビットの解釈 シェーダ型 シェーダ値(チャンネル転送関数) 書き込み値 T(逆チャンネル転送関数)
8unorm 8 符号なし整数 v ∈ {0,...,255} f32 v ÷ 255 max(0, min(1, T))
8snorm 8 符号付き整数 v ∈ {-128,...,127} f32 v ÷ 127 max(-1, min(1, T))
8uint 8 符号なし整数 v ∈ {0,...,255} u32 v min(255, T)
8sint 8 符号付き整数 v ∈ {-128,...,127} i32 v max(-128, min(127, T))
16unorm 16 符号なし整数 v ∈ {0,...,65535} f32 v ÷ 65535 max(0, min(1, T))
16snorm 16 符号付き整数 v ∈ {-32768,...,32767} f32 v ÷ 32767 max(-1, min(1, T))
16uint 16 符号なし整数 v ∈ {0,...,65535} u32 v min(65535, T)
16sint 16 符号付き整数 v ∈ {-32768,...,32767} i32 v max(-32768, min(32767, T))
16float 16 IEEE-754 binary16 16ビット浮動小数点値 v f32 v quantizeToF16(T)
32uint 32 32ビット符号なし整数値 v u32 v T
32sint 32 32ビット符号付き整数値 v i32 v T
32float 32 IEEE-754 binary32 32ビット浮動小数点値 v f32 v T
2unorm 2 符号なし整数 v ∈ {0,...,3} f32 v ÷ 3 max(0, min(1, T))
2uint 2 符号なし整数 v ∈ {0,...,3} u32 v min(3, T)
10unorm 10 符号なし整数 v ∈ {0,...,1023} f32 v ÷ 1023 max(0, min(1, T))
10uint 10 符号なし整数 v ∈ {0,...,1023} u32 v min(1023, T)
10float 10 10ビット浮動小数点値:5ビットバイアス指数、5ビット仮数 v f32 v max(0, T)
11float 11 11ビット浮動小数点値:5ビットバイアス指数、6ビット仮数 v f32 v max(0, T)

以下のストレージテクスチャ用テクセルフォーマット表のテクセルフォーマットは、WebGPU plain color formatsに対応し、WebGPU STORAGE_BINDING用途で少なくとも1つのアクセスモードをサポートします。 これらのテクセルフォーマットはストレージテクスチャ型(§ 6.5.5 ストレージテクスチャ型)のパラメータとして使われます。

テクセルフォーマットが4チャンネルすべてを持たない場合:

下表の最後の列は、チャンネルフォーマット表のフォーマット固有チャンネル転送関数を使用しています。

ストレージテクスチャ用テクセルフォーマット
テクセルフォーマット チャンネルフォーマット メモリ順チャンネル 対応するシェーダ値
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))
rgba16snorm 16snorm r, g, b, a vec4<f32>(CTF(r), CTF(g), CTF(b), CTF(a))
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)
rg8snorm 8snorm r, g vec4<f32>(CTF(r), CTF(g), 0.0, 1.0)
rg8uint 8uint r, g vec4<u32>(CTF(r), CTF(g), 0u, 1u)
rg8sint 8sint r, g vec4<i32>(CTF(r), CTF(g), 0, 1)
rg16unorm 16unorm r, g vec4<f32>(CTF(r), CTF(g), 0.0, 1.0)
rg16snorm 16snorm r, g vec4<f32>(CTF(r), CTF(g), 0.0, 1.0)
rg16uint 16uint r, g vec4<u32>(CTF(r), CTF(g), 0u, 1u)
rg16sint 16sint r, g vec4<i32>(CTF(r), CTF(g), 0, 1)
rg16float 16float r, g vec4<f32>(CTF(r), CTF(g), 0.0, 1.0)
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)
r8snorm 8snorm r vec4<f32>(CTF(r), 0.0, 0.0, 1.0)
r8uint 8uint r vec4<u32>(CTF(r), 0u, 0u, 1u)
r8sint 8sint r vec4<i32>(CTF(r), 0, 0, 1)
r16unorm 16unorm r vec4<f32>(CTF(r), 0.0, 0.0, 1.0)
r16snorm 16snorm r vec4<f32>(CTF(r), 0.0, 0.0, 1.0)
r16uint 16uint r vec4<u32>(CTF(r), 0u, 0u, 1u)
r16sint 16sint r vec4<i32>(CTF(r), 0, 0, 1)
r16float 16float r vec4<f32>(CTF(r), 0.0, 0.0, 1.0)
rgb10a2unorm r, g, b: 10unorm a: 2unorm r, g, b, a vec4<f32>(CTF(r), CTF(g), CTF(b), CTF(a))
rgb10a2uint r, g, b: 10uint a: 2uint r, g, b, a vec4<u32>(CTF(r), CTF(g), CTF(b), CTF(a))
rg11b10ufloat r, g: 11float b: 10float r, g, b vec4<f32>(CTF(r), CTF(g), CTF(b), 1.0)

WGSLは、表内の各テクセルフォーマットについて事前宣言列挙値を用意しています。

6.5.2. サンプルテクスチャ型

サンプルテクスチャは、 サンプラーと組み合わせてアクセスできます。 サンプラーを使わずにアクセスすることも可能です。 サンプルテクスチャは読み出しアクセスのみ許可します。

テクセルフォーマットは、テクスチャ変数にバインドされた GPUTextureformat 属性です。 WebGPU は、テクスチャ、バインドグループレイアウトの sampleType、 およびテクスチャ変数の サンプル型 の互換性を 検証します。

テクスチャはサンプル型でパラメータ化され、 必ず f32i32u32のいずれかでなければなりません。

次元性 配列化
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 あり

6.5.3. マルチサンプルテクスチャ型

マルチサンプルテクスチャサンプル数が1以上です。 名前に反して、サンプラーと組み合わせて使うことはできません。 実質的に、サンプルインデックスを無視すれば各論理テクセルアドレスごとに複数のテクセル分のデータを保持します。

テクセルフォーマットは、テクスチャ変数にバインドされた GPUTextureformat 属性です。 WebGPU は、テクスチャ、バインドグループレイアウトの sampleType、 およびテクスチャ変数の サンプル型 の互換性を 検証します。

texture_multisampled_2dサンプル型でパラメータ化され、 必ず f32i32u32のいずれかでなければなりません。

次元性 配列化
texture_multisampled_2d<T> 2D なし
texture_depth_multisampled_2d 2D なし

6.5.4. 外部サンプルテクスチャ型

外部テクスチャは不透明な2次元float-サンプルテクスチャ型であり、texture_2d<f32>に似ていますが、異なる表現を持つ可能性があります。 textureLoadtextureSampleBaseClampToEdgeなどの組み込み関数で読み出しでき、これらは異なる表現を扱います。

WebGPU § 6.4 GPUExternalTexture参照。

次元性 配列化
texture_external 2D なし

6.5.5. ストレージテクスチャ型

ストレージテクスチャは、サンプラーを使わず個別テクセル値へのアクセスをサポートします。

ストレージテクスチャ型は、ストレージテクスチャ用テクセルフォーマットのいずれかでパラメータ化されなければなりません。 テクセルフォーマットにより§ 6.5.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 なし

6.5.6. 深度テクスチャ型

深度テクスチャは、 sampler_comparisonと組み合わせてアクセス可能です。 サンプラーを使わずにアクセスすることもできます。 深度テクスチャは読み出しアクセスのみ許可されます。

テクスチャのテクセルフォーマットGPUTextureBindingLayoutで定義されます。

次元性 配列化
texture_depth_2d 2D なし
texture_depth_2d_array 2D あり
texture_depth_cube Cube なし
texture_depth_cube_array Cube あり

6.5.7. サンプラー型

サンプラーは、サンプルテクスチャ深度テクスチャへのアクセスを調整し、以下の操作を組み合わせて行います:

サンプラー型は以下の通りです:

説明
sampler サンプラー。サンプルテクスチャへのアクセスを調整します。
sampler_comparison 比較サンプラー。深度テクスチャへのアクセスを調整します。

サンプラーはWebGPU APIで生成時にパラメータ化され、WGSLモジュールでは変更できません。

サンプラーはテクスチャ組み込み関数でのみ使用できます。

sampler
sampler_comparison

6.6. AllTypes型

AllTypes型は、WGSLのすべてのの集合です。

AllTypes型はWGSLソースで記述する方法はありません。

すべての§ 6.9 事前宣言型・型ジェネレータ一覧を参照してください。

注:型は通常の意味での値ではありません。 実行時にシェーダで操作されるデータではありません。

AllTypes型が存在する理由は、型チェック規則が、通常の値を含み得る句に適用されるようにするためです。 WGSLでは型も値の一種と定義し、式が型を表せるようにすることで、規則を一貫性のあるものにしています。

主な例はテンプレートパラメータであり、様々な文脈で型、列挙値プレーン値など複数のものを表します。 特にtemplate_arg_expression文法規則はexpression文法非終端記号に展開されます。

6.7. 型エイリアス

型エイリアスは既存の型に新しい名前を付けて宣言するものです。 宣言は必ずモジュールスコープで行い、そのスコープはプログラム全体です。

Tが構造体型S型エイリアスとして定義された場合、 Sのメンバーのすべての属性を含むプロパティはTにも継承されます。

注: エイリアスされる型が value constructor の組み込み関数をサポートしている場合、 型エイリアスが スコープ内 であり、関数呼び出しが他の点で有効な場合は、 その関数を元の型名ではなくエイリアス名から呼び出すことができます。

type_alias_decl

'alias' ident '=' type_specifier

例:型エイリアス
alias Arr = array<i32, 5>;

alias RTArr = array<vec4<f32>>;

alias single = f32;     // f32のエイリアス宣言
const pi_approx: single = 3.1415;
fn two_pi() -> single {
  return single(2) * pi_approx;
}

6.8. 型指定子文法

§ 8.17 型式参照。

type_specifier

template_elaborated_ident

template_elaborated_ident

ident _disambiguate_template template_list ?

注:も型を表すことができます。これはprimary_expression文法規則からtemplate_elaborated_identに展開され、括弧付き式経由でも表せます。

6.9. 事前宣言型・型ジェネレータ一覧

WGSLソースで記述可能な事前宣言は以下の通りです:

WGSLはfrexpmodfatomicCompareExchangeWeak組み込み関数の戻り値型も事前宣言しますが、WGSLソースで記述することはできません。

事前宣言型ジェネレータは下表の通りです:

事前宣言型ジェネレータ
事前宣言型ジェネレータ 参照先
array § 6.2.9 配列型参照
atomic § 6.2.8 アトミック型参照
mat2x2 § 6.2.7 行列型参照(行列型の型エイリアスも一覧)

注:これらは値コンストラクタ式でも行列生成に使われます。

mat2x3
mat2x4
mat3x2
mat3x3
mat3x4
mat4x2
mat4x3
mat4x4
ptr § 6.4.3 参照型・ポインター型参照
texture_1d § 6.5.2 サンプルテクスチャ型参照
texture_2d
texture_2d_array
texture_3d
texture_cube
texture_cube_array
texture_multisampled_2d § 6.5.3 マルチサンプルテクスチャ型参照
texture_storage_1d § 6.5.5 ストレージテクスチャ型参照
texture_storage_2d
texture_storage_2d_array
texture_storage_3d
vec2 § 6.2.6 ベクトル型参照(ベクトル型の型エイリアスも一覧)

注:これらは値コンストラクタ式でもベクトル生成に使われます。

vec3
vec4

7. 変数・値の宣言

変数宣言値宣言は、データ値に名前を与えます。

値宣言は値に名前を付け、その値は宣言後不変です。 値宣言にはconstoverridelet、仮引数宣言の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;

これらの宣言は必ず型または初期化子を明示指定しなければなりません。 型・初期化子の両方指定も可能です。 これらの宣言は関連データ値の型、すなわち宣言の有効値型を決定します。 有効値型は以下の通りです:

値宣言・変数宣言の各種は、初期化子式や有効値型に追加の制約を課す場合があります。

変数・値宣言機能まとめ
宣言 可変性 スコープ 有効値型1 初期化子サポート 初期化子式2 リソースインターフェースの一部
const 不変 モジュールまたは関数 構築可能型具象型または抽象型必須 定数式 いいえ
override 不変 モジュール 具象スカラー 任意3 定数式またはoverride式 いいえ4
let 不変 関数 具象 構築可能型または ポインター型 必須 定数式override式実行時式 いいえ
var<storage, read>
var<storage>
不変 モジュール 具象 ホスト共有型 不可 はい。
ストレージバッファ
var<storage, read_write>5,6 可変 モジュール 具象 ホスト共有型 不可 はい。
ストレージバッファ
var<uniform> 不変 モジュール 具象 構築可能型 ホスト共有型 不可 はい。
ユニフォームバッファ
var6 不変7 モジュール テクスチャ型 不可 はい。
テクスチャリソース
var 不変 モジュール サンプラー型 不可 はい。
サンプラーリソース
var<workgroup>6,8 可変 モジュール 具象 プレーン型固定フットプリントあり9 不可10 いいえ
var<private> 可変 モジュール 具象 構築可能型 任意10 定数式またはoverride式 いいえ
var<function>
var
可変 関数 具象 構築可能型 任意10 定数式override式実行時式 いいえ
  1. const宣言のみ抽象型を許可し、型を明示指定しない場合のみ該当。

  2. 式の型は自動変換可能有効値型にできなければならない。

  3. 初期化子未指定の場合、パイプライン生成時に値を与える必要あり。

  4. override宣言はシェーダインターフェースの一部だが、バインドリソースではない。

  5. ストレージバッファストレージテクスチャは、read以外のアクセスモードでは静的アクセスできません。WebGPU createBindGroupLayout()参照。

  6. アトミック型は可変ストレージバッファかworkgroup変数のみ可。

  7. ストレージテクスチャwriteread_writeアクセスモードでデータが可変だが、変更はtextureStore組み込み関数のみ可能。変数自体は変更不可。

  8. workgroupアドレス空間の変数はコンピュートシェーダステージでのみ静的アクセス可能。

  9. 最外層配列要素数override式でも可。

  10. 初期化子がない場合、変数はデフォルト初期化される。

7.1. 変数と値の違い

変数宣言はWGSLモジュールで唯一可変なデータです。 値宣言は常に不変です。 変数は参照型ポインター型値の基礎となりますが、値宣言はポインターや参照型値の基礎にはなりません。

変数の利用は値宣言より一般にコストが高く、変数利用は変数に紐付くメモリ位置への読み出し書き込み操作が追加されるためです。

一般に、次の順で宣言を使うのが推奨されます(上ほど推奨):

この順に使うことで、シェーダ全体の性能が最も高くなります。

7.2. 値の宣言

識別子解決されて値宣言を指す場合、その識別子はその値を表します。

WGSLは複数種の値宣言を提供します。 それぞれの宣言種の値は、シェーダライフサイクルの異なるタイミングで確定します。 宣言種ごとに値が確定するタイミングは以下の通りです:

注: 仮引数については§ 11 関数で説明されています。

7.2.1. const宣言

const宣言は、シェーダ生成時に確定するデータ値に名前を与えます。 const宣言は必ず初期化子が必要です。 モジュールスコープまたは関数スコープで宣言できます。 初期化子式は必ず 定数式でなければなりません。 const宣言の型は具象型または抽象型構築可能型でなければなりません。 const宣言だけが有効値型として抽象型を持てます。

注: 抽象数値型はWGSLで記述できないため、型推論経由のみ使用可能です。

例: モジュールスコープでの const 宣言
const a = 4;                  // 値が 4 の AbstractInt。
const b : i32 = 4;            // 値が 4 の i32。
const c : u32 = 4;            // 値が 4 の u32。
const d : f32 = 4;            // 値が 4 の f32。
const e = vec3(a, a, a);      // 値が (4, 4, 4) の AbstractInt の vec3。
const f = 2.0;                // 値が 2 の AbstractFloat。
const g = mat2x2(a, f, a, f); // AbstractFloat の mat2x2 の値:
                              // ((4.0, 2.0), (4.0, 2.0))。
                              // AbstractInt a は AbstractFloat に変換される。
                              // AbstractFloat は AbstractInt に変換できない。
const h = array(a, f, a, f);  // 4 要素の AbstractFloat の array:
                              // (4.0, 2.0, 4.0, 2.0)。

7.2.2. override宣言

override宣言は、パイプライン上書き可能な定数値に名前を付けます。 override宣言は必ずモジュールスコープで宣言します。 パイプライン上書き可能定数値はパイプライン生成時に確定します。 WebGPUパイプライン生成メソッドで指定された値があればそれが使われ、なければ具象化された初期化子式の値が使われます。 override宣言の有効値型具象スカラー型でなければなりません。

初期化子式は省略可能です。 ある場合はoverride式でなければならず、これはパイプライン上書き可能定数のデフォルト値を表します。 初期化子がない場合、パイプライン生成時に値が与えられないとパイプライン生成エラーとなります。

宣言にid属性が付与されている場合、そのリテラルはパイプライン定数IDと呼ばれ、0〜65535の一意な整数でなければなりません。 2つのoverride宣言が同じパイプライン定数IDを使うことはできません。

アプリケーションは、パイプライン生成時にoverride宣言に対して独自の値を指定できます。 パイプライン生成APIは、上書き可能な定数からその定数型の値へのマッピングを受け付けます。 定数はパイプライン上書き可能定数識別子文字列によって識別されます。これは、パイプライン定数IDが指定されていればその10進表現、指定されていなければ宣言された名前です。

例:モジュール定数、パイプライン上書き可能
@id(0)    override has_point_light: bool = true;  // アルゴリズム制御
@id(1200) override specular_param: f32 = 2.3;     // 数値制御
@id(1300) override gain: f32;                     // 必ず上書きされる必要あり
          override width: f32 = 0.0;              // APIレベルで"name"で指定
          override depth: f32;                    // APIレベルで"depth"で指定。必ず上書き必要
          override height = 2 * depth;            // デフォルト値(APIで未指定の場合)、他の上書き可能定数に依存

7.2.3. let宣言

let宣言は、実行時に文が実行されるたびに値が確定する名前を定義します。 let宣言は関数スコープのみで宣言可能であり、動的コンテキストです。 let宣言は必ず初期化子式が必要です。 値は初期化子の具象化された値です。 let宣言の有効値型具象構築可能型またはポインター型でなければなりません。

例:関数スコープで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>となります。 変数の格納型は常に具象型です。

変数宣言は以下を行います:

識別子が変数宣言を解決する場合、その識別子は変数のメモリへの参照メモリビューを表す式となり、その型は変数の参照型です。§ 8.11 変数識別子式参照。

変数宣言のアドレス空間アクセスモードをWGSLソースで指定する場合は、varキーワード後にテンプレートリストで記述します:

privatestorageuniformworkgrouphandleモジュールスコープのみ、 function関数スコープのみ宣言可。 handleとfunction以外のアドレス空間は必ず指定しなければならず、handleは指定不可。 functionアドレス空間指定はオプション。

アクセスモードは必ずデフォルト値を持ち、storage以外ではWGSLソースに指定不可です。§ 14.3 アドレス空間参照。

uniformアドレス空間の変数はユニフォームバッファ変数です。 格納型はホスト共有かつ構築可能型で、アドレス空間レイアウト制約を満たす必要があります。

storageアドレス空間の変数はストレージバッファ変数です。 格納型はホスト共有型で、アドレス空間レイアウト制約を満たす必要があります。 readまたはread_writeアクセスモードで宣言可能で、デフォルトはreadです。

テクスチャリソースは、有効値型がテクスチャ型の変数です。 モジュールスコープで宣言され、基底のテクセルグリッドへアクセスするための不透明ハンドルを持ちます。 ハンドル自体はhandleアドレス空間にあり、常にread-onlyです。 多くの場合、基底テクセルもread-onlyで、テクスチャ変数は不変とされます。 書き込み専用ストレージテクスチャ読書き両用ストレージテクスチャでは基底テクセルが可変なので、テクスチャ変数は慣習的に可変とされます。

サンプラーリソースは、有効値型がサンプラー型の変数です。 モジュールスコープで宣言され、handleアドレス空間に存在し、不変です。

§ 13.3.2 リソースインターフェースで述べたように、ユニフォームバッファ・ストレージバッファ・テクスチャ・サンプラーはシェーダのリソースインターフェースを構成します。

変数の有効期間は、シェーダ実行中その変数に割り当てられたメモリ位置が維持される期間です。 モジュールスコープ変数の有効期間はシェーダステージの全実行期間です。 privatefunctionアドレス空間の変数は呼び出しごとに独立したバージョンを持ちます。 関数スコープ変数は動的コンテキストです。 関数スコープ変数の有効期間はスコープによって決まります:

2つのリソース変数が重複メモリ位置を持つ場合、どちらかが可変なら動的エラーです。 その他の変数は有効期間が重なっても重複メモリ位置は持ちません。 変数の有効期間が終わると、そのメモリは他の変数用に使われることがあります。

注: WGSLは変数の内容が有効期間中のみ可視となることを保証します。

privatefunctionworkgroupアドレス空間の変数は生成時に初期値を持ちます。 初期化子がなければ初期値はデフォルト初期値です。 初期値は以下のように決定されます:

他のアドレス空間の変数は、描画コマンドディスパッチコマンドでバインドされたリソースによって設定されます。

以下はWGSLコード例です:

例:変数の初期値
var i: i32;         // 初期値は0。推奨されないスタイル。
loop {
  var twice: i32 = 2 * i;   // 各イテレーションごとに再評価
  i++;
  if i == 5 { break; }
}
ループ本体は6回実行されます。 変数iは0, 1, 2, 3, 4, 5の値を、変数twiceは0, 2, 4, 6, 8の値を取ります。

以下はWGSLコード例です:

例:変数の複数回読み出し
var x: f32 = 1.0;
let y = x * x + x + 1;
xは変数なので、すべてのアクセスはロード/ストア操作となります。 ただし、ブラウザやドライバが中間表現最適化により冗長なロードを除去することが期待されます。
例:モジュールスコープの変数宣言
var<private> decibels: f32;
var<workgroup> worklist: array<i32,10>;

struct Params {
  specular: f32,
  count: i32
}

// ユニフォームバッファ。常にread-onlyで、レイアウト制約が厳しい。
@group(0) @binding(2)
var<uniform> param: Params;    // ユニフォームバッファ

// 読み書き可能なストレージバッファ
@group(0) @binding(0)
var<storage,read_write> pbuf: array<vec2<f32>>;

// テクスチャとサンプラーは常に"handle"空間
@group(0) @binding(1)
var filter_params: sampler;
例:バッファのアクセスモード
// ストレージバッファ
@group(0) @binding(0)
var<storage,read> buf1: Buffer;       // 読み出しのみ、書き込み不可
@group(0) @binding(0)
var<storage> buf2: Buffer;            // 読み出しのみ、書き込み不可
@group(0) @binding(1)
var<storage,read_write> buf3: Buffer; // 読み書き可能

struct ParamsTable {weight: f32}

// ユニフォームバッファ。常にread-onlyで、レイアウト制約が厳しい。
@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_or_value_statement :

variable_decl

| variable_decl '=' expression

| 'let' optionally_typed_ident '=' expression

| 'const' optionally_typed_ident '=' expression

variable_decl :

'var' _disambiguate_template template_list ? optionally_typed_ident

optionally_typed_ident :

ident ( ':' type_specifier ) ?

global_variable_decl :

attribute * variable_decl ( '=' expression ) ?

global_value_decl :

'const' optionally_typed_ident '=' expression

| attribute * 'override' optionally_typed_ident ( '=' expression ) ?

8.

は値の計算方法を指定します。

値式の種類ごとに、評価タイミングと表現力とのトレードオフがあります。 早い評価ほど操作が制約されますが、値の利用できる場所が増えます。このトレードオフにより、値宣言ごとに異なる柔軟性が生じます。 定数式override式は、GPUの実行前に評価されるため、最終GPUコードには式の計算結果のみが必要です。 また、定数式シェーダ生成時に評価されるため、override式より多くの場面で利用できます(例:関数スコープ変数配列サイズ指定など)。 実行時式は、定数式でもoverride式でもない式です。 実行時式はシェーダ実行中GPU上で計算されます。 実行時式は利用できる文法要素が少ないですが、他の実行時値などより広い式から計算可能です。

8.1. 早期評価式

WGSLは実行時前に評価可能な2種類の式を定義します:

8.1.1. const

シェーダ生成時に評価できる式をconst式と呼びます。 式がconst式となるのは、そのすべての識別子が以下のいずれかに解決される場合です:

const式の型は必ず型規則により生成時固定フットプリント型に決定されなければなりません。

注: 抽象型はconst式の型推論で用いられることがあります。

const式Eは、以下の場合のみ評価されます

注: この評価規則により、短絡評価演算子&&||は右辺部分式の評価をガードします。ただし、部分式が静的型決定のために評価を要する場合は除きます。

const式はWebGPU APIメソッドを実装するCPUによって評価される場合があります。 したがって、AbstractFloat値の演算の精度要件は、WebGPUの一般的な実行環境(WebAssembly [WASM-CORE-2]やECMAScript [ECMASCRIPT]など)で要求される以上に厳しくありません。 具体的な浮動小数点型(f32など)の精度要件は§ 15.7.4.1 具体的浮動小数点式の精度で規定されています。

例:(42) の解析:

例:-5 の解析:

例:-2147483648 の解析:

例:const minint = -2147483648; の解析:

例:let minint = -2147483648; の解析:

例:false && (10i < i32(5 * 1000 * 1000 * 1000)) の解析:

例:false && array<u32, 1 + 2>(0, 1, 2)[0] == 0

8.1.2. override

パイプライン生成時に評価できる式はoverride式と呼びます。 式がoverride式となるのは、そのすべての識別子が以下のいずれかに解決される場合です:

注: すべてのconst式はoverride式でもあります。

const式以外のoverride式は、パイプライン生成時にのみ検証・評価され、APIで提供された値がoverride宣言に代入された後のみです。 override宣言がAPI経由で値を代入された場合、初期化子式があっても評価されません。 それ以外の場合、override式Eは以下の場合のみ評価されます

注: すべてのoverride式がoverride宣言の初期化子として使えるわけではありません。なぜなら、初期化子は型規則具象スカラー型に決定されなければならないためです。

例:override x = 42; の解析:

例:let y = x + 1; の解析:

例:vec3(x,x,x) の解析:

例:override式によるシェーダ生成エラー
override a : i32 = 0;
override b = a / 0; // シェーダ生成エラー
                    // cをoverrideしようとしても関係なく発生
例:override式によるパイプライン生成エラー
override a : i32 = 0;
override b = 1 / a;

// bはfrag1シェーダの一部。frag1をパイプラインにコンパイルする場合:
// * bがoverrideされていればエラーなし
// * aが非ゼロ値にoverrideされていればエラーなし
// * aが0かつbがoverrideされていなければパイプライン生成エラー
@fragment
fn frag1() {
  _ = b;
}

// bはfrag2シェーダには含まれない。frag2をパイプラインにコンパイルする場合:
// bがoverrideされていなくてもaが0でもエラーにならない。
@fragment
fn frag2() {
}

8.2. 不定値

限定された場合に、実行時式の評価が、その部分式に対して非対応値を使ったときに生じ得ます。

この場合、評価結果は式の静的型不定値となり、 これは静的型における実装依存の任意値を意味します。

評価が繰り返しごとなど複数の動的コンテキストで生じる場合、個々に異なる値が生成されることがあります。 例:ループ各イテレーションごとに異なる値になる場合があります。

注: 型が浮動小数点型かつ実装がNaN値をサポートする場合、実行時の不定値はNaNとなる可能性があります。

例: 不定値の例
fn fun() {
   var extracted_values: array<i32,2>;
   const v = vec2<i32>(0,1);

   for (var i: i32 = 0; i < 2 ; i++) {
      // 実行時式によってベクトルをインデックスし、ベクトルのインデックス範囲外の場合、
      // ベクトル成分型の不定値が生成される。
      let extract = v[i+5];

      // この時点で 'extract' は i32 型の任意の値。

      // 後で使うため保存。
      extracted_values[i] = extract;

      if extract == extract {
         // これは常に実行される
      }
      if extract < 2 {
         // 実行される場合もあるが、されない場合もある。
         // 元のベクトル成分は 0 と 1 だが、
         // 抽出された値がそれらとは限らない。
      }
   }
   if extracted_values[0] == extracted_values[1] {
      // 実行される場合もあるが、されない場合もある。
   }
}

fn float_fun(runtime_index: u32) {
   const v = vec2<f32>(0,1); // 浮動小数点値のベクトル

   // 前の例と同様に、'float_extract' は不定値となる。
   // 浮動小数点型なので、NaN になる場合がある。
   let float_extract: f32 = v[runtime_index+5];

   if float_extract == float_extract {
      // これは *実行されない場合がある*、理由:
      //  - 'float_extract' が NaN の場合があり、
      //  - NaN は他のどの浮動小数点数とも等しくない(他の NaN でさえも)。
   }
}

8.3. リテラル値式

スカラーリテラル型規則
前提条件 結論 説明
true: bool trueの論理値。
false: bool falseの論理値。
eがサフィックスなし整数リテラルの場合 e: AbstractInt 抽象整数リテラル値。
eがサフィックスなし浮動小数点リテラルの場合 e: AbstractFloat 抽象浮動小数点リテラル値。
eiサフィックス付き整数リテラルの場合 e: i32 32ビット符号付き整数リテラル値。
euサフィックス付き整数リテラルの場合 e: u32 32ビット符号なし整数リテラル値。
efサフィックス付き浮動小数点リテラルの場合 e: f32 32ビット浮動小数点リテラル値。
ehサフィックス付き浮動小数点リテラルの場合 e: f16 16ビット浮動小数点リテラル値。

8.4. 括弧付き式

括弧付き式の型規則
前提条件 結論 説明
e : T ( e ) : T eとして評価される。
式を周囲のテキストから分離するために括弧を使う。

8.5. 合成値分解式

この節では、構成要素を持つ合成値から構成要素を取得する式、 および、合成値へのメモリビューから構成要素への参照を取得する式について説明します。 ここでは、合成値またはそのメモリビューを基底と呼びます。

方法は2つあります:

名前付き要素式

基底 Bの式の後にピリオド'.'(U+002D)と要素名を続ける。

  • Bベクトル型または構造体型、またはそのメモリビューのときに利用可能。

  • 有効な名前はBの型に依存。

インデックス式

基底式の後に'['(U+005B)、インデックス式、']'(U+005D)を続ける。

これら2つの構文は、component_or_swizzle_specifier文法規則で表されます。

インデックス式のインデックス値iは、0 ≤ i < Nのとき有効範囲インデックスです。ここで、Nは合成型の要素数です:

インデックス値が有効範囲インデックスでない場合、範囲外インデックスです。 範囲外インデックスは多くの場合プログラムの欠陥であり、多くの場合エラーとなります。 詳細は下記参照。

さらに、ベクトル型は別のベクトルの構成要素から新しいベクトル値を作るスウィズル構文もサポートします。

8.5.1. ベクトル要素アクセス式

ベクトルの構成要素へは:

便宜名称は.記法でアクセス(例: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: T
e.r: T
eの第1要素を選択

これは1文字のスウィズル

e: vecN<T>
e.y: T
e.g: T
eの第2要素を選択

これは1文字のスウィズル

e: vecN<T>
Nは3または4
e.z: T
e.b: T
eの第3要素を選択

これは1文字のスウィズル

e: vec4<T> e.w: T
e.a: T
eの第4要素を選択

これは1文字のスウィズル

e: vecN<T>
i: i32 または u32
T具象型
e[i]: T ベクトルのi番目要素を選択
最初の要素はi=0。

iが範囲[0,N-1]外の場合:

e: vecN<T>
i: i32 または u32
T抽象型
iconst式
e[i]: T ベクトルのi番目要素を選択
最初の要素はi=0。

iが範囲[0,N-1]外ならシェーダ生成エラー

注: 抽象ベクトル値eをconst式でない式でインデックスすると、インデックス適用前に具象化されます。

8.5.1.2. ベクトル複数要素選択

この節の式はすべて複数文字のスウィズルです。 それぞれが他のベクトルの構成要素からベクトルを生成します。

複数文字のスウィズル代入の左辺には使えません: 代入の左辺は参照型でなければなりませんが、複数文字スウィズル式は常にベクトル型の値を生成します。

ベクトル分解:複数要素選択
前提条件 結論 説明
e: vecN<T> または ptr<AS,vecN<T,AM>>
Ix, y, z, wのいずれか
Jx, y, z, wのいずれか
AMreadまたはread_write
e.IJ: vec2<T>
第1要素e.I、第2要素e.Jの2要素ベクトルを生成。
zNが3または4の時のみ有効。
wNが4の時のみ有効。

eがポインターの場合、間接参照後にロード規則が適用される。
e: vecN<T> または ptr<AS,vecN<T,AM>>
Ir, g, b, aのいずれか
Jr, g, b, aのいずれか
AMreadまたはread_write
e.IJ: vec2<T>
第1要素e.I、第2要素e.Jの2要素ベクトルを生成。
bNが3または4の時のみ有効。
aNが4の時のみ有効。

eがポインターの場合、間接参照後にロード規則が適用される。
e: vecN<T> または ptr<AS,vecN<T,AM>>
I, J, Kx, y, z, wのいずれか
AMreadまたはread_write
e.IJK: vec3<T>
第1要素e.I、第2要素e.J、第3要素e.Kの3要素ベクトルを生成。
zNが3または4の時のみ有効。
wNが4の時のみ有効。

eがポインターの場合、間接参照後にロード規則が適用される。
e: vecN<T> または ptr<AS,vecN<T,AM>>
I, J, Kr, g, b, aのいずれか
AMreadまたはread_write
e.IJK: vec3<T>
第1要素e.I、第2要素e.J、第3要素e.Kの3要素ベクトルを生成。
bNが3または4の時のみ有効。
aNが4の時のみ有効。

eがポインターの場合、間接参照後にロード規則が適用される。
e: vecN<T> または ptr<AS,vecN<T,AM>>
I, J, K, Lx, y, z, wのいずれか
AMreadまたはread_write
e.IJKL: vec4<T>
第1要素e.I、第2要素e.J、第3要素e.K、第4要素e.Lの4要素ベクトルを生成。
zNが3または4の時のみ有効。
wNが4の時のみ有効。

eがポインターの場合、間接参照後にロード規則が適用される。
e: vecN<T> または ptr<AS,vecN<T,AM>>
I, J, K, Lr, g, b, aのいずれか
AMreadまたはread_write
e.IJKL: vec4<T>
第1要素e.I、第2要素e.J、第3要素e.K、第4要素e.Lの4要素ベクトルを生成。
bNが3または4の時のみ有効。
aNが4の時のみ有効。

eがポインターの場合、間接参照後にロード規則が適用される。

注: 上表では参照型ロード規則で暗黙的に扱われます。

8.5.1.3. ベクトルメモリビューからの要素参照

この節の式は、ベクトル全体のメモリビューからベクトルの単一要素のメモリビューを生成します。

WGSLの型規則により、これらの式は以下の場合に利用できます:

ベクトル要素への書き込みアクセスは、ベクトルに関連付けられたメモリ位置全体をアクセスする場合があります。

注: これは、異なるinvocationでベクトルメモリの異なる要素にアクセスし、少なくとも一方が書き込みアクセスの場合は同期が必要となることを意味します。§ 17.11 同期組み込み関数参照。

ベクトルのメモリビューから要素への参照取得
前提条件 結論 説明
r: ref<AS,vecN<T>,AM> または
ptr<AS,vecN<T>,AM>
r.x: ref<AS,T,AM>
r.r: ref<AS,T,AM>
メモリビューrが参照するベクトルの第1要素への参照を取得。
結果参照の元変数rの元変数と同じ。
r: ref<AS,vecN<T>,AM> または
ptr<AS,vecN<T>,AM>
r.y: ref<AS,T,AM>
r.g: ref<AS,T,AM>
メモリビューrが参照するベクトルの第2要素への参照を取得。
結果参照の元変数rの元変数と同じ。
r: ref<AS,vecN<T>,AM> または
ptr<AS,vecN<T>,AM>
Nは3または4
r.z: ref<AS,T,AM>
r.b: ref<AS,T,AM>
メモリビューrが参照するベクトルの第3要素への参照を取得。
結果参照の元変数rの元変数と同じ。
r: ref<AS,vec4<T>,AM> または
ptr<AS,vec4<T>,AM>
r.w: ref<AS,T,AM>
r.a: ref<AS,T,AM>
メモリビューrが参照するベクトルの第4要素への参照を取得。
結果参照の元変数rの元変数と同じ。
r: ref<AS,vecN<T>,AM> または
ptr<AS,vecN<T>,AM>
i: i32 または u32
r[i] : ref<AS,T,AM>
メモリビューrが参照するベクトルのi番目要素への参照を取得

iが範囲[0,N-1]外の場合:

結果参照の元変数rの元変数と同じ。

8.5.2. 行列要素アクセス式

列ベクトル抽出
前提条件 結論 説明
e: matCxR<T>
i: i32 または u32
T具象型
e[i]: vecR<T> ei番目の列ベクトルを返す。

iが範囲[0,C-1]外の場合:

e: matCxR<T>
i: i32 または u32
T抽象型
iconst式
e[i]: vecR<T> ei番目の列ベクトルを返す。

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抽象型
iconst式
e[i] : T e配列値のi番目の要素の値を返す。

iが範囲[0,N-1]外ならシェーダ生成エラー

注: 抽象配列値eをconst式でない式でインデックスすると、インデックス適用前に具象化されます。

配列メモリビューから要素への参照取得
前提条件 結論 説明
r: ref<AS,array<T,N>,AM> または
ptr<AS,array<T,N>,AM>
i: i32 または u32
r[i] : ref<AS,T,AM> メモリビューrが参照する配列のi番目の要素への参照を取得

iが範囲[0,N-1]外の場合:

結果参照の元変数rの元変数と同じ。

r: ref<AS,array<T>,AM> または
ptr<AS,array<T>,AM>
i: i32 または u32
r[i] : ref<AS,T,AM> 実行時サイズ配列のメモリビューrが参照する配列のi番目の要素への参照を取得

実行時に配列がN要素なら、iが範囲[0,N-1]外の場合は不正メモリ参照評価となる。

iが符号付き整数で0未満の場合:

結果参照の元変数rの元変数と同じ。

8.5.4. 構造体要素アクセス式

構造体メンバー抽出
前提条件 結論 説明
Sは構造体型
MSのメンバー名(型T
e: S
e.M: T e構造体値のメンバー名Mの値を返す。
構造体メモリビューからメンバーへの参照取得
前提条件 結論 説明
Sは構造体型
MSのメンバー名(型T
r: ref<AS,S,AM> または
ptr<AS,S,AM>
r.M: ref<AS,T,AM> 構造体メモリビューから、識別子名Mの構造体メンバーへの参照を取得。
結果参照の元変数rの元変数と同じ。

8.6. 論理式

単項論理演算
前提条件 結論 説明
e: T
TはboolまたはvecN<bool>
!e: T 論理否定。 efalseなら結果はtrueetrueならfalseTがベクトルなら構成要素ごと
二項論理式
前提条件 結論 説明
e1: bool
e2: bool
e1 || e2: bool 短絡"or"。e1またはe2がtrueなら結果はtruee1がfalseの場合のみe2を評価。
e1: bool
e2: bool
e1 && e2: bool 短絡"and"。e1e2がともにtrueなら結果はtruee1がtrueの場合のみe2を評価。
e1: T
e2: T
TはboolまたはvecN<bool>
e1 | e2: T 論理"or"。Tがベクトルなら構成要素ごとe1e2を両方評価。
e1: T
e2: T
TはboolまたはvecN<bool>
e1 & e2: T 論理"and"。Tがベクトルなら構成要素ごとe1e2を両方評価。

8.7. 算術式

単項算術式
前提条件 結論 説明
e: T
TはAbstractInt, AbstractFloat, i32, f32, f16, vecN<AbstractInt>, vecN<AbstractFloat>, vecN<i32>, vecN<f32>, または vecN<f16>
-e: T 符号反転。Tがベクトル型の場合構成要素ごとに適用。 T整数スカラー型でeが最小負値の場合、結果はe
二項算術式
前提条件 結論 説明
e1 : T
e2 : T
SはAbstractInt, AbstractFloat, i32, u32, f32, f16
TはSまたはvecN<S>
e1 + e2 : T 加算。Tがベクトル型の場合構成要素ごとに適用。

Tが浮動小数点型の場合、スカラー定義域は以下を除く拡張実数(x,y)の組:

  • (−∞,+∞)

  • (+∞,−∞)

e1 : T
e2 : T
SはAbstractInt, AbstractFloat, i32, u32, f32, f16
TはSまたはvecN<S>
e1 - e2 : T 減算。Tがベクトル型の場合構成要素ごとに適用。

Tが浮動小数点型の場合、スカラー定義域は以下を除く拡張実数(x,y)の組:

  • (−∞,−∞)

  • (+∞,+∞)

e1 : T
e2 : T
SはAbstractInt, AbstractFloat, i32, u32, f32, f16
TはSまたはvecN<S>
e1 * e2 : T 乗算。Tがベクトル型の場合構成要素ごとに適用。

Tが浮動小数点型の場合、スカラー定義域は以下を除く拡張実数(x,y)の組:

  • (0,−∞)

  • (0,+∞)

  • (−∞, 0)

  • (+∞, 0)

e1 : T
e2 : T
SはAbstractInt, AbstractFloat, i32, u32, f32, f16
TはSまたはvecN<S>
e1 / e2 : T 除算。Tがベクトル型の場合構成要素ごとに適用。

Tが符号付き整数スカラー型の場合:

注: 切り捨て動作の保証には符号なし除算より多くの演算が必要になる場合があります。 両被演算子が同符号と判明している場合は符号なし除算を使うこと。

Tが符号なし整数スカラー型の場合:

Tが浮動小数点型の場合、スカラー定義域は以下を除く拡張実数(x,y)の組:

  • (0,0)

  • (−∞,−∞)

  • (−∞,+∞)

  • (+∞,−∞)

  • (+∞,+∞)

e1 : T
e2 : T
SはAbstractInt, AbstractFloat, i32, u32, f32, f16
TはSまたはvecN<S>
e1 % e2 : T 剰余。Tがベクトル型の場合構成要素ごとに適用。

Tが符号付き整数スカラー型の場合、e1e2を1回ずつ評価し、結果は:

注: 非ゼロの場合、結果はe1と同符号。

注: 一貫した動作保証には符号なし剰余より多くの演算が必要になる場合があります。

Tが符号なし整数スカラー型の場合、結果は:

Tが浮動小数点型の場合、結果はe1 - e2 * trunc(e1 / e2)。

Tが浮動小数点型の場合、スカラー定義域は以下を除く拡張実数(x,y)の組:

  • x / yの定義域外:

    • (0,0)

    • (−∞,−∞)

    • (−∞,+∞)

    • (+∞,−∞)

    • (+∞,+∞)

  • さらにy * trunc(x / y)の定義域外:

    • yが無限大かつx有限→trunc(x / y)は0

    • yが0かつxが無限大→trunc(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>
行列加算:結果は構成要素ごとに計算され、結果の列ie1[i] + e2[i]
e1 - e2: matCxR<T> 行列減算:結果は構成要素ごとに計算され、結果の列ie1[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>
線形代数の行列-列ベクトル積: 結果の構成要素idot(transpose(m)[i],v)
m: matCxR<T>
v: vecR<T>
TはAbstractFloat, f32, f16
v * m: vecC<T>
線形代数の行ベクトル-行列積:
transpose(transpose(m) * transpose(v))
e1: matKxR<T>
e2: matCxK<T>
TはAbstractFloat, f32, f16
e1 * e2: matCxR<T>
線形代数の行列積。

8.8. 比較式

比較
前提条件 結論 説明
e1: T
e2: T
SはAbstractInt, AbstractFloat, bool, i32, u32, f32, f16
TSまたはvecN<S>
TBTがベクトルの場合vecN<bool>、それ以外はbool
e1 == e2: TB 等価。Tがベクトル型の場合構成要素ごと
e1: T
e2: T
SはAbstractInt, AbstractFloat, bool, i32, u32, f32, f16
TSまたはvecN<S>
TBTがベクトルの場合vecN<bool>、それ以外はbool
e1 != e2: TB 非等価。Tがベクトル型の場合構成要素ごと
e1: T
e2: T
SはAbstractInt, AbstractFloat, i32, u32, f32, f16
TはSまたはvecN<S>
TBTがベクトルの場合vecN<bool>、それ以外はbool
e1 < e2: TB より小さい。Tがベクトル型の場合構成要素ごと
e1: T
e2: T
SはAbstractInt, AbstractFloat, i32, u32, f32, f16
TはSまたはvecN<S>
TBTがベクトルの場合vecN<bool>、それ以外はbool
e1 <= e2: TB 以下。Tがベクトル型の場合構成要素ごと
e1: T
e2: T
SはAbstractInt, AbstractFloat, i32, u32, f32, f16
TはSまたはvecN<S>
TBTがベクトルの場合vecN<bool>、それ以外はbool
e1 > e2: TB より大きい。Tがベクトル型の場合構成要素ごと
e1: T
e2: T
SはAbstractInt, AbstractFloat, i32, u32, f32, f16
TはSまたはvecN<S>
TBTがベクトルの場合vecN<bool>、それ以外はbool
e1 >= e2: TB 以上。Tがベクトル型の場合構成要素ごと

8.9. ビット式

単項ビット演算
前提条件 結論 説明
e: T
SはAbstractInt, i32, u32のいずれか
TはSまたはvecN<S>
~e : T eに対するビット単位の補数。 結果の各ビットはeの対応するビットの反転値。 Tがベクトル型の場合構成要素ごと
二項ビット演算
前提条件 結論 説明
e1: T
e2: T
SはAbstractInt, i32, u32のいずれか
TはSまたはvecN<S>
e1 | e2: T ビット単位OR。Tがベクトル型の場合構成要素ごと
e1: T
e2: T
SはAbstractInt, i32, u32のいずれか
TはSまたはvecN<S>
e1 & e2: T ビット単位AND。Tがベクトル型の場合構成要素ごと
e1: T
e2: T
SはAbstractInt, i32, u32のいずれか
TはSまたはvecN<S>
e1 ^ e2: T ビット単位排他的OR。Tがベクトル型の場合構成要素ごと
ビットシフト式
前提条件 結論 説明
e1: T
e2: TS
Sはi32またはu32
TはSまたはvecN<S>
TSTがSのときu32、そうでなければvecN<u32>
e1 << e2: T 左シフト(シフト値は具体的な値):

e1を左シフトし、下位ビットにはゼロを挿入、上位ビットは破棄。

シフトするビット数はe2の値(e1のビット幅でmod)。
e2e1のビット幅以上の場合:

両方がシェーダ実行開始前に分かっている場合、結果はオーバーフローしない必要:

Tがベクトル型の場合構成要素ごと

e1: T
e2: TS
TはAbstractIntまたはvecN<AbstractInt>
TSTがAbstractIntのときu32、そうでなければvecN<u32>
e1 << e2: T 左シフト(シフト値は抽象値):

e1を左シフトし、下位ビットにはゼロを挿入、上位ビットは破棄。

シフトするビット数はe2の値。

e1の最上位e2+1個のビットは必ず同じ値でなければならない。そうでない場合はオーバーフロー。

注: この条件は、破棄されるビットが元値の符号ビットと同じで、結果値の符号ビットとも同じである必要があることを意味します。

Tがベクトル型の場合構成要素ごと

e1: T
e2: TS
Sはi32またはu32
TはSまたはvecN<S>
TSTがSのときu32、そうでなければvecN<u32>
e1 >> e2: T 右シフト(シフト値は具体的な値)。

e1を右シフトし、下位ビットを破棄。

Sが符号なし型なら、上位ビットにはゼロを挿入。

Sが符号付き型なら:

  • e1が負なら、挿入される各ビットは1、結果も負。

  • それ以外は挿入ビットは0。

シフトするビット数はe2e1のビット幅でmod)。

e2e1のビット幅以上の場合:

Tがベクトル型の場合構成要素ごと

e1: T
e2: TS
TはAbstractIntまたはvecN<AbstractInt>
TSTがAbstractIntのときu32、そうでなければvecN<u32>
e1 >> e2: T 右シフト(抽象値)。

e1を右シフトし、下位ビットを破棄。

e1が負なら挿入ビットは1、結果も負。そうでなければ0。

シフトするビット数はe2の値。

Tがベクトル型の場合構成要素ごと

8.10. 関数呼び出し式

関数呼び出し式は、呼び出し先関数が戻り値型を持つ関数呼び出しを実行します。 呼び出し関数が値を返さない場合は、関数呼び出し文を使います。 § 9.5 関数呼び出し文参照。

8.11. 変数識別子式

変数名から参照取得
前提条件 結論 説明
v識別子で、解決先が アドレス空間ASに宣言された 格納型TアクセスモードAMスコープ内変数 v: ref<AS,T,AM> 変数名vのメモリへの参照が結果。

8.12. 仮引数式

関数の仮引数として宣言された識別子の値取得
前提条件 結論 説明
a識別子で、解決先が スコープ内の仮引数宣言(型T a: T 関数呼び出し時の呼び出し元オペランドで渡された値。

8.13. アドレス取得式

アドレス取得演算子は参照を対応するポインタに変換します。

参照からポインタ取得
前提条件 結論 説明
r: ref<AS,T,AM> &r: ptr<AS,T,AM> 結果は、参照値rと同じメモリビューに対応するポインタ値。

r不正メモリ参照なら、結果ポインタも不正メモリ参照。

AShandleアドレス空間のときシェーダ生成エラー

rベクトル要素への参照のときシェーダ生成エラー

8.14. 間接参照式

間接参照演算子はポインタを対応する参照に変換します。

ポインタから参照取得
前提条件 結論 説明
p: ptr<AS,T,AM> *p: ref<AS,T,AM> 結果は、ポインタ値pと同じメモリビューに対応する参照値。

p不正メモリ参照なら、結果参照も不正メモリ参照。

8.15. 値宣言の識別子式

constoverridelet宣言された識別子の値取得
前提条件 結論 説明
c識別子で、解決先が スコープ内const宣言(型T c: T 初期化式を評価した値。 式はconst式で、シェーダ生成時に評価される。
c識別子で、解決先が スコープ内override宣言(型T c: T パイプライン生成時に定数IDに値が指定された場合、その値。 パイプラインごとに異なる場合あり。

それ以外の場合は初期化式の評価値。 パイプライン上書き可能定数はモジュールスコープに現れるので、評価はシェーダ実行開始前。

注: API呼び出しで初期値未指定かつlet宣言に初期化式がない場合、パイプライン生成失敗。

c識別子で、解決先が スコープ内let宣言(型T c: T 初期化式を評価した値。 let宣言は関数本体内に現れ、初期化は制御フローが宣言に到達するたびに評価される。

8.16. 列挙式

列挙式
前提条件 結論 説明
e識別子で、解決先が事前宣言列挙値 であり、列挙型Eに属する e : E § 6.3.1 事前宣言列挙値参照

8.17. 型式

型式
前提条件 結論 説明
t識別子で、解決先が事前宣言 t : AllTypes § 6.9 事前宣言型・型ジェネレーターまとめ参照
a識別子で、解決先が型エイリアス a : AllTypes さらに、aはエイリアス先の型を表します。
s識別子で、解決先が構造体型宣言 s : AllTypes さらに、sはその構造体型を表します。
tg識別子で、解決先が型ジェネレーター

e1: T1
...
eN: TN

tg _template_args_start
e1,
...,
eN
_template_args_end
: AllTypes
型ジェネレーターは必要なテンプレートパラメータの要件を独自に定めており、 テンプレートパラメータが結果型決定方法を定義します。

e1eNテンプレートパラメータ

例:型式vec2<f32>f32要素2つのベクトル。

§ 6.9 事前宣言型・型ジェネレーターまとめに型ジェネレーター一覧あり。

注: この2つのバリエーションは、eNの後にカンマがあるかどうかのみが異なります。

tg _template_args_start
e1,
...,
eN,
_template_args_end
: AllTypes

8.18. 式文法まとめ

識別子call_phraseの最初のトークンの場合、次のいずれかです:

宣言とスコープの規則により、これらの名前は常に区別されます。

primary_expression :

template_elaborated_ident

| call_expression

| literal

| paren_expression

call_expression :

call_phrase

注: call_expression規則は、呼び出し式に型チェックを適用するために存在します。

call_phrase :

template_elaborated_ident argument_expression_list

paren_expression :

'(' expression ')'

argument_expression_list :

'(' expression_comma_list ? ')'

expression_comma_list :

expression ( ',' expression ) * ',' ?

component_or_swizzle_specifier :

'[' expression ']' component_or_swizzle_specifier ?

| '.' member_ident component_or_swizzle_specifier ?

| '.' swizzle_name component_or_swizzle_specifier ?

unary_expression :

singular_expression

| '-' unary_expression

| '!' unary_expression

| '~' unary_expression

| '*' unary_expression

| '&' unary_expression

singular_expression :

primary_expression component_or_swizzle_specifier ?

lhs_expression :

core_lhs_expression component_or_swizzle_specifier ?

| '*' lhs_expression

| '&' lhs_expression

core_lhs_expression :

ident _disambiguate_template

| '(' lhs_expression ')'

multiplicative_expression :

unary_expression

| multiplicative_expression multiplicative_operator unary_expression

multiplicative_operator :

'*'

| '/'

| '%'

additive_expression :

multiplicative_expression

| additive_expression additive_operator multiplicative_expression

additive_operator :

'+'

| '-'

shift_expression :

additive_expression

| unary_expression _shift_left unary_expression

| unary_expression _shift_right unary_expression

relational_expression :

shift_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

| shift_expression '==' shift_expression

| shift_expression '!=' shift_expression

short_circuit_and_expression :

relational_expression

| short_circuit_and_expression '&&' relational_expression

short_circuit_or_expression :

relational_expression

| short_circuit_or_expression '||' relational_expression

binary_or_expression :

unary_expression

| binary_or_expression '|' unary_expression

binary_and_expression :

unary_expression

| binary_and_expression '&' unary_expression

binary_xor_expression :

unary_expression

| binary_xor_expression '^' unary_expression

bitwise_expression :

binary_and_expression '&' unary_expression

| binary_or_expression '|' unary_expression

| binary_xor_expression '^' unary_expression

expression :

relational_expression

| short_circuit_or_expression '||' relational_expression

| short_circuit_and_expression '&&' relational_expression

| bitwise_expression

8.19. 演算子の優先順位と結合規則

この節全体は非規範的です。

右辺WGSL式の演算子の優先順位と結合規則は、まとめると文法から現れます。右辺式は演算子をグループ化して整理し、次の図で示されるように構成されます:

演算子の優先順位と結合規則のグラフ

可読性を高めるために、以下のグループは他のグループとは結合しません:

そして以下のグループは自身とは結合しません:

これらのグループセクション両方を結合するには、関係を明示的に設定するため括弧が必要です。次の例では、これらの規則がコメント内で式を無効にする場所を示します:

例: 演算子の優先順位の隅のケース
let a = x & (y ^ (z | w)); // 無効: x & y ^ z | w
let b = (x + y) << (z >= w); // 無効: x + y << z >= w
let c = x < (y > z); // 無効: x < y > z
let d = x && (y || z); // 無効: x && y || z

優先順位によって式の暗黙の括弧が制御され、より強い結合の演算子は弱い優先順位の演算子と一緒に現れる場合、括弧で囲まれているかのように動作します。例えば、乗算演算子が加算より強い場合、式 a + b * c から (a + (b * c)) が推論されます。同様に、結合規則によってこれらの暗黙の括弧の方向が制御されます。例えば、左から右への結合は a + b + c 式から ((a + b) + c) を推論し、右から左への結合は * * a 式から (* (* a)) を推論します。

次の表は、演算子の優先順位、結合規則、結合対象をまとめており、強いものから弱いものへと並べています。結合対象欄には、各演算子のより強い式が記載されています。例えば「All above」と書かれている場合、この演算子はそれより強い式すべてを含むことができます。一方、「Unary」と書かれている場合、単項より弱くこの演算子より強いものは括弧が必要です。この欄は演算子を線形に並べるために必要です。

右辺式の演算子の優先順位、結合規則、および結合対象(強いものから弱いものへソート)
名前 演算子 結合規則 結合対象
括弧付き (...)
a(), a[], a.b 左から右
単項 -a, !a, ~a, *a, &a 右から左 上記すべて
乗算 a*b, a/b, a%b 左から右 上記すべて
加算 a+b, a-b 左から右 上記すべて
シフト a<<b, a>>b 括弧が必要 単項
関係 a<b, a>b, a<=b, a>=b, a==b, a!=b 括弧が必要 上記すべて
ビット単位 AND a&b 左から右 単項
ビット単位 XOR a^b 左から右 単項
ビット単位 OR a|b 左から右 単項
ショートサーキット AND a&&b 左から右 関係
ショートサーキット OR a||b 左から右 関係

9.

は、実行を制御するプログラムの断片です。 文は通常、順次実行されますが、制御フロー文によって非順次に実行される場合があります。

9.1. 複合文

複合文は、中括弧で囲まれた0個以上の文の並びです。 それらの文の中に宣言が含まれる場合、その識別子は、 次の文の開始から複合文の終わりまでスコープ内になります。

compound_statement :

attribute * '{' statement * '}'

continuing_compound_statementは、複合文の特殊な形式であり、 continuing文の本体を構成し、最後にbreak-if文を任意で許容します。

9.2. 代入文

代入は、式を評価し、必要に応じてメモリに格納(つまり変数の内容を更新)します。

assignment_statement :

lhs_expression ( '=' | compound_assignment_operator ) expression

| '_' '=' expression

演算子トークンの左側のテキストを左辺、 演算子トークンの右側の式を右辺と呼びます。

9.2.1. 単純代入

代入は、 単純代入である場合、 左辺が式であり、演算子がイコール('=')トークンです。 この場合、右辺の値が左辺で参照されるメモリに書き込まれます。

事前条件 説明
e: T,
T具体的な構築可能型,
r: ref<AS,T,AM>,
ASは書き込み可能なアドレス空間,
アクセスモード AMwriteまたはread_write
r = e rを評価し、次にeを評価し、eで計算された値を rが参照するメモリ位置に書き込みます。

注: 参照が無効なメモリ参照の場合、書き込みが実行されない場合や、 予期しないメモリ位置に書き込まれる場合があります。

最も単純な場合、左辺は変数名です。 その他のケースについては§ 6.4.8 参照値とポインタ値の形成を参照してください。

例: 代入
struct S {
    age: i32,
    weight: f32
}
var<private> person: S;

fn f() {
    var a: i32 = 20;
    a = 30;           // 'a' の内容を 30 に置き換える。

    person.age = 31;  // person 変数の age フィールドに 31 を書き込む。

    var uv: vec2<f32>;
    uv.y = 1.25;      // uv の第2成分に 1.25 を格納。

    let uv_x_ptr: ptr<function,f32> = &uv.x;
    *uv_x_ptr = 2.5;  // uv の第1成分に 2.5 を格納。

    var sibling: S;
    // person 変数の内容を sibling 変数にコピーする。
    sibling = person;
}

9.2.2. ダミー代入

代入ダミー代入である場合、 左辺がアンダースコア('_')トークンです。 この場合、右辺は評価され、その後無視されます。

事前条件 説明
e: T,
T構築可能型、ポインタ型テクスチャ型、またはサンプラー型
_ = e eを評価します。

注: 得られた値は保存されません。 _トークンは識別子ではないため、式で使用できません。

ダミー代入は以下のような用途で便利です:

例: 不要な関数結果を捨てるためのダミー代入の利用
var<private> counter: i32;

fn increment_and_yield_previous() -> i32 {
  let previous = counter;
  counter = counter + 1;
  return previous;
}

fn user() {
  // counter をインクリメントするが、結果は使わない。
  _ = increment_and_yield_previous();
}
例: バインディングを占有するためだけにダミー代入を使う
struct BufferContents {
    counter: atomic<u32>,
    data: array<vec4<f32>>
}
@group(0) @binding(0) var<storage> buf: BufferContents;
@group(0) @binding(1) var t: texture_2d<f32>;
@group(0) @binding(2) var s: sampler;

@fragment
fn shade_it() -> @location(0) vec4<f32> {
  // buf, t, s がシェーダインターフェイスの一部であることを宣言するが、何も利用しない。
  _ = &buf;
  _ = t;
  _ = s;
  return vec4<f32>();
}

9.2.3. 複合代入

代入は、 複合代入である場合、 左辺が式であり、 演算子がcompound_assignment_operatorsのいずれかです。

compound_assignment_operator :

'+='

| '-='

| '*='

| '/='

| '%='

| '&='

| '|='

| '^='

| _shift_right_assign

| _shift_left_assign

各文の型要件・意味論・挙動は、以下の表のように複合代入が展開されるものとして定義されています。ただし、

展開
e1 += e2 e1 = e1 + (e2)
e1 -= e2 e1 = e1 - (e2)
e1 *= e2 e1 = e1 * (e2)
e1 /= e2 e1 = e1 / (e2)
e1 %= e2 e1 = e1 % (e2)
e1 &= e2 e1 = e1 & (e2)
e1 |= e2 e1 = e1 | (e2)
e1 ^= e2 e1 = e1 ^ (e2)
e1 >>= e2 e1 = e1 >> (e2)
e1 <<= e2 e1 = e1 << (e2)

注: 構文上、複合代入ダミー代入になることはできません。

注: 参照e1は一度評価されますが、基となるメモリには2回アクセスされます。 まず読み取りアクセスで古い値を取得し、 次に書き込みアクセスで更新値を保存します。

例: 複合代入
var<private> next_item: i32 = 0;

fn advance_item() -> i32 {
   next_item += 1;   // next_item に 1 を加算。
   return next_item - 1;
}

fn bump_item() {
  var data: array<f32,10>;
  next_item = 0;
  // data[0] に 5.0 を加算、advance_item() は一度だけ呼ばれる。
  data[advance_item()] += 5.0;
  // この時点で next_item は 1。
}

fn precedence_example() {
  var value = 1;
  // 複合代入の右辺は独立した式として評価される。
  value *= 2 + 3; // value = value * (2 + 3); と同じ。
  // 'value' は 5 になる。
}
注: 複合代入は、単純代入を使う別のWGSLコードとして書き換えることもできます。 ポイントは、参照の評価結果を一度だけ保持するためにポインタを使うことです。
例えば、 e1がベクトルの成分への参照でない場合は、
e1+=e2;
は次のように書き換えられます。
{ let p = &(e1); *p = *p + (e2); }
ここで識別子pは、プログラム内の他の識別子と異なるものを選びます。
e1がベクトル成分への参照の場合、上記の手法はWGSLでアドレス取得ができないため修正が必要です。 例えばevがベクトルへの参照の場合、文
ev[c] += e2;
は次のように書き換えられます。
{ let p = &(ev); let c0 = c; (*p)[c0] = (*p)[c0] + (e2); }
ここで識別子c0pは、プログラム内の他の識別子と異なるものを選びます。

9.3. インクリメント文とデクリメント文

インクリメント文は、変数の内容に1を加算します。 デクリメント文は、変数の内容から1を減算します。

increment_statement :

lhs_expression '++'

decrement_statement :

lhs_expression '--'

この式は必ず 具体的な 整数スカラー ストア型read_write アクセスモードを持つ参照として評価されなければなりません。

事前条件 説明
r : ref<AS,T,read_write>,
T具体的な 整数スカラー
r++ rが参照するメモリ内容に1を加算します。
r += T(1) と同じ
r : ref<AS,T,read_write>,
T具体的な 整数スカラー
r-- rが参照するメモリ内容から1を減算します。
r -= T(1) と同じ
例: インクリメントとデクリメント
fn f() {
    var a: i32 = 20;
    a++;
    // この時点で a は 21
    a--;
    // この時点で a は 20
}

9.4. 制御フロー

制御フロー文によってプログラムが非順次に実行される場合があります。

9.4.1. if文

if文は、条件式の評価に基づいて最大1つの複合文を条件付きで実行します。

if文はif節、0個以上のelse if節、任意のelse節で構成されます。

if_statement :

attribute * if_clause else_if_clause * else_clause ?

if_clause :

'if' expression compound_statement

else_if_clause :

'else' 'if' expression compound_statement

else_clause :

'else' compound_statement

型規則の事前条件: 各ifおよびelse if節の式は必ずbool型でなければなりません。

if文の実行方法は以下の通りです:

9.4.2. switch文

switch文は、セレクタ式の評価に応じて、case節のいずれか、またはdefault節に制御を移します。

switch_statement :

attribute * 'switch' expression switch_body

switch_body :

attribute * '{' switch_clause + '}'

switch_clause :

case_clause

| default_alone_clause

case_clause :

'case' case_selectors ':' ? compound_statement

default_alone_clause :

'default' ':' ? compound_statement

case_selectors :

case_selector ( ',' case_selector ) * ',' ?

case_selector :

'default'

| expression

case節は、'case'トークンの後にカンマ区切りのcaseセレクタのリストと、複合文形式の本体が続くものです。

default単独節は、'default'トークンの後に、複合文形式の本体が続きます。

default節は、以下のいずれかです:

各switch文は必ず1つだけdefault節を持たなければなりません。

'default'トークンは、1つのcase_selectorリスト内に複数回現れてはなりません

型規則の事前条件: 1つのswitch文について、セレクタ式および全てのcaseセレクタ式は必ず同じ具体的な整数スカラー型でなければなりません。

case_selectors内の式は必ず 定数式である必要があります。

同じswitch文内の2つの異なるcaseセレクタ式が同じ値を持ってはなりません

セレクタ値がcase_selectorリスト内の式の値と等しい場合、 制御はそのcase節の本体に移ります。 セレクタ値がどのcaseセレクタ値とも等しくない場合、制御はdefault節の本体に移ります。

節の本体の終わりに達すると、制御はswitch文の直後の最初の文に移ります。

節の本体内の文の1つが宣言である場合、 通常のスコープライフタイム規則が適用されます。 すなわち、本体は文の並びであり、その中に宣言がある場合、その宣言のスコープは並びの次の文の開始から本体の終わりまで拡張します。 宣言は到達時に実行され、新しい変数またはのインスタンスを作成し、初期化します。

例: WGSLのswitch
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;
  }
}
例: defaultを組み合わせたWGSLのswitch
const c = 2;
var a : i32;
let x : i32 = generateValue();
switch x {
  case 0: { 
    a = 1;
  }
  case 1, c {       // caseセレクタに定数式を使える
    a = 3;
  }
  case 3, default { // defaultキーワードを他節と組み合わせ可能
    a = 4;
  }
}

9.4.3. loop文

loop_statement :

attribute * 'loop' attribute * '{' statement * continuing_statement ? '}'

loop文は、ループ本体を繰り返し実行します。 ループ本体は複合文として指定されます。 ループ本体の各実行を反復と呼びます。

この繰り返しは、breakまたは return文によって中断される場合があります。

オプションで、ループ本体の末尾にcontinuing文を配置できます。

動的エラーは、 loopが無限回の反復を実行する場合に発生します。 これはループの早期終了、他の非局所的な効果、あるいはデバイスロスにつながることがあります。

ループ本体内の文の1つが宣言である場合、 通常のスコープライフタイム規則が適用されます。 すなわち、ループ本体は文の並びであり、その中に宣言がある場合、その宣言のスコープは並びの次の文の開始からループ本体の終わりまで拡張します。 宣言は到達するたびに実行されるため、各反復ごとに新しい変数またはのインスタンスが作成され、再初期化されます。

注: loop文は特殊な構文であり、一般的にはforwhile文を使うことを推奨します。loop文は他のシェーダ言語との最大の違いのひとつです。

この設計は、コンパイル済みコードでよく見られるループイディオムを直接表現しています。 特に、ループ更新文をループ本体の末尾に配置することで、本体内で定義された値を自然に利用できます。

例: for文
var a: i32 = 2;
for (var i: i32 = 0; i < 4; i++) {
  a *= 2;
}
例: loop文
var a: i32 = 2;
var i: i32 = 0;      // <1>
loop {
  if i >= 4 { break; }

  a = a * 2;

  i++;
}
例: continueを使ったfor文
var a: i32 = 2;
let step: i32 = 1;
for (var i: i32 = 0; i < 4; i += step) {
  if (i % 2 == 0) { continue; }
  a *= 2;
}
例: continueを使ったloop文
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;
}
例: continueとcontinuingを使ったloop文
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;
  }
}

9.4.4. for文

for_statement :

attribute * 'for' '(' for_header ')' compound_statement

for_header :

for_init ? ';' expression ? ';' for_update ?

for_init :

variable_or_value_statement

| variable_updating_statement

| func_call_statement

for_update :

variable_updating_statement

| func_call_statement

for ステートメントは、複合ステートメント に含まれる ループ ステートメントの構文糖衣です。 一般的に、for ステートメントは以下の形式を取ります。

for ( initializer ; condition ; update_part ) { body }

条件式が存在する場合、for ステートメントは次の形式のループに展開されます:

{
    initializer ;
    loop {
        if !(condition) { break; }
        body
        continuing { update_part }
    }
}
条件式が存在しない場合、for ステートメントは次の形式のループに展開されます:
{
    initializer ;
    loop {
        body
        continuing { update_part }
    }
}

さらに:

for ループの initializer は、ループが実行される前に一度だけ実行されます。 宣言 が initializer に現れる場合、その 識別子スコープ内 にあり、body の終了まで有効です。 body 内の宣言とは異なり、この宣言は各イテレーションで再初期化されません。

conditionbody、および update_part はこの順序で実行され、ループの イテレーション を形成します。 body は特別な形式の 複合ステートメント です。 body 内の宣言の識別子は、次のステートメントの開始からbody の終了まで スコープ内 にあります。 この宣言は到達するたびに実行されるため、各新しいイテレーションは変数または定数の新しいインスタンスを作成し、それを再初期化します。

例: 条件付きの For から Loop への変換: 変換前
var a: i32 = 2;
for (var i: i32 = 0; i < 4; i++) {
  if a == 0 {
    continue;
  }
  a = a + 2;
}

変換後:

例: 条件付きの For から Loop への変換: 変換後
var a: i32 = 2;
{ // i 変数用に新しいスコープを導入
  var i: i32 = 0;
  loop {
    if !(i < 4) {
      break;
    }

    if a == 0 {
      continue;
    }
    a = a + 2;

    continuing {
      i++;
    }
  }
}
例: 条件なしの For から Loop への変換: 変換前
var a: i32 = 2;
for (var i: i32 = 0; ; i++) {
  if a == 0 {
    continue;
  }
  if i == 4 { break; }
  a = a + 2;
}

変換後:

例: 条件なしの For から Loop への変換: 変換後
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文

while_statement :

attribute * 'while' expression compound_statement

while文は、条件でパラメータ化されるループの一種です。 各ループ反復の開始時に、 真偽値条件が評価されます。 条件が偽のとき、whileループは実行を終了します。 そうでない場合は反復の残りが実行されます。

型規則の事前条件: 条件は必ずbool型でなければなりません。

whileループはloop文またはfor文の構文糖とみなせます。 以下の文形式は同等です:

動的エラーは、 whileループが無限回の反復を実行する場合に発生します。 これはループの早期終了、他の非局所的な効果、あるいはデバイスロスにつながることがあります。

9.4.6. break文

break_statement :

'break'

break文は、最も近い囲みのループ またはswitch文の本体直後へ制御を移し、 そのループまたはswitch文の実行を終了します。

break文は必ず loopforwhile、 およびswitch文の中だけで使われなければなりません。

break文は、ループのcontinuing文から抜け出すような位置に置いてはなりません。 代わりにbreak-if文を使用してください。

例: continuing句からのbreakはWGSLでは無効
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_statement :

'break' 'if' expression ';'

break-if文は真偽値条件を評価します。 条件がtrueであれば、最も近い囲みのloop文の本体直後に制御が移り、そのループの実行が終了します。

型規則の事前条件: 条件は必ずbool型でなければなりません。

注: break-if文はcontinuing 文の本体の最後の文としてのみ現れることができます。

例: 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;
    break if i >= 4;
  }
}

9.4.8. continue文

continue_statement :

'continue'

continue文は最も近い囲みのloop文において以下のように制御を移します:

continue文は必ずループforまたはwhile文の中でのみ使用しなければなりません。 continue文は絶対に外側のcontinuing文へ制御を移すような位置に置いてはいけません。 (continuing文への分岐は前方分岐です。)

continue文は絶対に対象となるcontinuing文で使用される宣言を飛ばして制御を移す位置に置いてはいけません。

注: continuecontinuing文内で使用する場合、 continuing文の中にネストされた別のループ内から制御フローを移す場合のみ使えます。 つまり、現在実行中のcontinuing文の先頭へ制御を移すためにcontinueを使うことはできません。

例: 宣言を飛ばすcontinueは無効
var i: i32 = 0;
loop {
  if i >= 4 { break; }
  if i % 2 == 0 { continue; } // <3>

  let step: i32 = 2;

  continuing {
    i = i + step;
  }
}

9.4.9. continuing文

continuing_statement :

'continuing' continuing_compound_statement

continuing_compound_statement :

attribute * '{' statement * break_if_statement ? '}'

continuing文は、ループ反復の末尾で実行される複合文を指定します。 この構文は任意です。

複合文は、どのネストレベルでもreturnを含んではなりません

9.4.10. return文

return_statement :

'return' expression ?

return文は現在の関数の実行を終了します。 関数がエントリポイントの場合、 現在のシェーダ呼び出しが終了します。 それ以外の場合は、現在の関数呼び出しの呼び出し箇所での評価が続行されます。

関数が戻り値型を持たない場合、return文は任意です。その場合、return文に値を指定してはなりません。 それ以外の場合は、式が必ず存在し、これを戻り値と呼びます。 この場合、関数呼び出し箇所は戻り値として評価されます。 戻り値の型は関数の戻り値型と一致しなければなりません

9.4.11. discard文

discard文は呼び出しを ヘルパー呼び出しに変換し、フラグメントを破棄します。 discard文は必ず フラグメントシェーダ段階でのみ使われなければなりません。

より厳密には、discard文の実行は次のことを行います:

discard文の前に実行された文のみが観測可能な効果を持ちます。

注: discard文は フラグメント段階の任意の関数で実行でき、効果は同じです: フラグメントは破棄されます。

例: discard文によるフラグメントの破棄
@group(0) @binding(0)
var<storage, read_write> will_emit_color : u32;

fn discard_if_shallow(pos: vec4<f32>) {
  if pos.z < 0.001 {
    // ここが実行される場合、will_emit_color変数は1にはならない。
    // ヘルパー呼び出しはshared memoryに書き込まないため。
    discard;
  }
  will_emit_color = 1;
}

@fragment
fn main(@builtin(position) coord_in: vec4<f32>)
  -> @location(0) vec4<f32>
{
  discard_if_shallow(coord_in);

  // ヘルパー関数がdiscard文を実行しなかった場合のみ、値1をセットし赤色を出す。
  will_emit_color = 1;
  return vec4<f32>(1.0, 0.0, 0.0, 1.0);
}

9.5. 関数呼び出し文

func_call_statement :

call_phrase

関数呼び出し文は関数呼び出しを実行します。

呼び出される関数にmust_use属性がある場合、シェーダ生成エラーとなります。

注: 関数が値を返す場合でも、 その関数にmust_use属性がなければ、 その値は無視されます。

9.6. 文の文法まとめ

statement規則は、関数本体内のほとんどの場所で使える文に一致します。

statement :

';'

| return_statement ';'

| if_statement

| switch_statement

| loop_statement

| for_statement

| while_statement

| func_call_statement ';'

| variable_or_value_statement ';'

| break_statement ';'

| continue_statement ';'

| 'discard' ';'

| variable_updating_statement ';'

| compound_statement

| assert_statement ';'

variable_updating_statement :

assignment_statement

| increment_statement

| decrement_statement

さらに、特定の文は非常に特定の文脈でのみ使用できます:

9.7. 文の挙動解析

9.7.1. 規則

制御フローに影響する一部の文は、特定のコンテキストでのみ有効です。 例えば、continueloopfor、または while の外では無効です。 さらに、均一性解析(§ 15.2 Uniformity参照)では、制御フローが複数の異なる方法で文を抜ける場合を判定する必要があります。

これら両方の目的は、文の実行挙動を要約するシステムによって達成されます。挙動解析は各文を、文の評価が完了した後に実行が進む可能な方法の集合へとマッピングします。 値や式に対する型解析と同様に、挙動解析もボトムアップで進行します:まず基本的な文の挙動を判定し、それから上位の構造に対して結合規則を適用して挙動を決定します。

挙動とは、次の要素を持つ集合です:

これらは複合文を抜ける方法に対応しており、キーワードによるものか、次の文へ進む("Next")ことによるものです。

s: B」は、s が挙動に関する規則を満たし、挙動 B を持つことを表します。

各関数について:

各関数には挙動を割り当てます:それは本体の挙動(本体を通常の文として扱う)、ただし "Return" は "Next" に置換されます。 上記の規則の結果として、関数挙動は常に {} または {Next} のいずれかになります。

挙動解析は、各文および関数について空でない挙動を判定できなければならない

文の挙動解析および検証のための規則
前提条件 結果の挙動
空文 {Next}
{s} s: B B
s1 s2

注: s1 はしばしばセミコロンで終わる。

s1: B1
B1 に Next がある
s2: B2
(B1∖{Next}) ∪ B2
s1: B1
B1 に Next がない
s2: B2
B1
var x:T; {Next}
let x = e; {Next}
var x = e; {Next}
x = e; {Next}
_ = e; {Next}
f(e1, ..., en); f の挙動 B がある B
return; {Return}
return e; {Return}
discard; {Next}
break; {Break}
break if e; {Break, Next}
continue; {Continue}
const_assert e; {Next}
if e s1 else s2 s1: B1
s2: B2
B1B2
loop {s1 continuing {s2}} s1: B1
s2: B2
B1 = {Return}
B2 に {Continue, Return} がない
{Return}
s1: B1
s2: B2
B1 ≠ {Return}
B2 に {Continue, Return} がない
(B1B2) に Break がない
(B1B2)∖{Continue, Next}
s1: B1
s2: B2
B1 ≠ {Return}
B2 に {Continue, Return} がない
(B1B2) に Break がある
(B1B2 ∪ {Next})∖{Break, Continue}
switch e {case c1: s1 ... case cn: sn} s1: B1
...
sn: Bn
(B1 ∪ ... ∪ Bn) に Break がない
B1 ∪ ... ∪ Bn
s1: B1
...
sn: Bn
(B1 ∪ ... ∪ Bn) に Break がある
(B1 ∪ ... ∪ Bn ∪ {Next})∖Break

注: ∪は集合の和演算、∖は集合の差分演算です。

注: 空文の場合は、loop の本体が空の場合や、for ループに初期化や更新文がない場合に該当します。

この解析の目的のため:

built-in functionは{Next}のbehaviorを持つ。 また、上記の表に記載されていない各演算子の適用も、同じオペランドを持つ関数呼び出しとして、関数の{Next}のbehaviorを持つかのような同じbehaviorを持つ。

関数のmustは、上記の規則を満たさなければならない。

Note: 式のbehaviorの解析は不要である。なぜなら、式は常に{Next}であるか、既に解析された関数がエラーを発生させているためである。

9.7.2. 補足

この節は情報提供のみであり、規範的ではありません。

挙動解析によって、プログラムは以下のような理由で拒否されることがあります (上記の要件を再掲):

この解析は、呼び出しグラフをボトムアップで解析することで線形時間で実行できます(関数呼び出しの挙動は関数のコードに依存するため)。

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}
}
例:if/thenは空のelseがあるものとして挙動する
fn if_example() {
  var a: i32 = 0;
  loop {
    if a == 5 {
      break;      // 挙動: {Break}
    }             // if複合文全体の挙動: {Break, Next},
                  //   ifには暗黙的な空のelseがある
    a = a + 1;    // 有効、前の文の挙動に"Next"があるため
  }
}
例:if/then/elseは両側の挙動を持つ
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}
  }
}
例:if/else if/elseは入れ子のif/elseのように挙動する
fn if_example() {
  var a: i32 = 0;
  loop {
    // if e1 s1 else if e2 s2 else s3
    // は次と同一:
    // if e1 else { if e2 s2 else s3 }
    if a == 5 {
      break;      // 挙動: {Break}
    } else if a == 42 {
      continue;   // 挙動: {Continue}
    } else {
      return;     // 挙動: {Return}
    }             // if複合文全体の挙動:
                  //   {Break, Continue, Return}
  }               // ループ複合文全体の挙動 {Next, Return}
}                 // 関数全体の挙動 {Next}
例:switchのBreakは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ではループは終了しない
fn invalid_infinite_loop() {
  loop {
    discard; // 挙動 { Next }
  }          // 無効、ループ全体の挙動は{ }。
}
例:条件付きcontinueとcontinuing文
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"に置き換えられる
}
例:冗長なcontinueとcontinuing文
fn redundant_continue_with_continuing() {
  var a: i32;
  loop {
    if a == 5 { break; }
    continue;   // 有効。冗長で、次の文へ分岐するだけ。
    continuing {
      a = a + 1;
    }
  }
}
例:ループ本体の末尾でのcontinue
fn continue_end_of_loop_body() {
  for (var i: i32 = 0; i < 5; i++ ) {
    continue;   // 有効。冗長で、
                //   ループ本体の末尾に分岐するだけ。
  }             // 挙動: {Next}、
                //   ループは"Continue"を吸収し、
                //   "for"ループは必ず"Next"を加える
}
forループはloopと条件付きbreakにデシュガーされます。前述の例の通り、条件付きbreakは挙動 {Break, Next}を持ち、これによりループの挙動に"Next"が加えられます。
例:戻り値型を持つ関数にはreturnが必要
fn missing_return () -> i32 {
  var a: i32 = 0;
  if a == 42 {
    return a;       // 挙動: {Return}
  }                 // 挙動: {Next, Return}
}                   // エラー: Nextは戻り値型を持つ関数の本体には無効
                    //   
例:continueはループ内でのみ有効
fn continue_out_of_loop () {
  var a: i32 = 0;
  if a > 0  {
    continue;       // 挙動: {Continue}
  }                 // 挙動: {Next, Continue}
}                   // エラー: 関数本体内ではContinueは無効
同じ例で、continuebreakに置き換えても、同じ理由で無効です。

10. アサーション

アサーションは、 ブール条件が満たされていることを検証するためのチェックです。

global_assert :

const_assert ';'

WGSLでは、アサーションの種類は一つ、 定数アサーションのみ定義されています。

const_assert :

'const_assert' expression

型規則の前提条件: 式は必ずbool型でなければなりません。

10.1. 定数アサーション文

定数アサーション文はアサーションの一種であり、 式がfalseとなった場合、シェーダー生成エラーを発生させます。 式は必ず定数式でなければなりません。 この文は、シェーダー内で静的アクセス条件を満たすことができますが、コンパイル後のシェーダーに対しては他に効果はありません。 定数アサーションはモジュールスコープまたは関数スコープとして記述できます。

assert_statement :

const_assert

例:静的アサーションの例
const x = 1;
const y = 2;
const_assert x < y; // モジュールスコープで有効。
const_assert(y != 0); // 括弧は省略可能。

fn foo() {
  const z = x + y - 2;
  const_assert z > 0; // 関数内で有効。
  let a  = 3;
  const_assert a != 0; // 無効、式は定数式でなければならない。
}

11. 関数

関数は、呼び出されたときに計算処理を実行します。

関数は次のいずれかの方法で呼び出されます:

WGSLの関数は、定義順序に制限がなく、使用より後に定義しても構いません。 そのため、関数プロトタイプや前方宣言は不要であり、その方法もありません。

関数には2種類あります:

11.1. ユーザー定義関数の宣言

関数宣言は、ユーザー定義関数を作成します。指定内容は以下の通りです:

関数宣言は必ずモジュールスコープでのみ記述可能です。 関数名はプログラム全体でスコープ内となります。

注:ユーザー定義関数オーバーロードを1つしか持ちません。

仮引数宣言は、関数呼び出し時に値として 必要となる識別子名と型を指定します。 仮引数には属性を付与できます。 § 11.2 関数呼び出し参照。 識別子のスコープ関数本体です。 同一関数の2つの仮引数は、同じ名前を持ってはなりません

注: 一部の組み込み関数では、抽象数値型の引数が許可される場合があります。 ただし、ユーザー宣言関数ではこの機能は現時点ではサポートされていません。

戻り値型を指定する場合は、必ず構築可能でなければなりません。

WGSLでは、関数宣言に付与できる属性は以下の通りです:

WGSLでは、関数の仮引数・戻り値型に付与できる属性は以下の通りです:

function_decl :

attribute * function_header compound_statement

function_header :

'fn' ident '(' param_list ? ')' ( '->' attribute * template_elaborated_ident ) ?

param_list :

param ( ',' param ) * ',' ?

param :

attribute * ident ':' type_specifier

例:単純な関数
// add_two関数の宣言。
// 仮引数は i と b の2つ。
// 戻り値型は i32。
// 本体はreturn文を持つ。
fn add_two(i: i32, b: f32) -> i32 {
  return i + 2;  // 仮引数は本体内で利用可能。
}

// コンピュートシェーダーのエントリーポイント関数 'main'。
// 戻り値型は指定なし。
// add_two関数を呼び出し、
// 結果を'six'という値に格納。
@compute @workgroup_size(1)
fn main() {
   let six: i32 = add_two(4, 5.0);
}

11.2. 関数呼び出し

関数呼び出しは、 関数を実行する文または式です。

関数呼び出しを含む関数は、呼び出し元関数または呼び出し元と呼ばれます。 実際に呼び出される関数は呼び出し先関数または呼び出し先です。

関数呼び出しは:

関数呼び出しは、必ず仮引数の数と 同じだけの引数値を呼び出し先関数に与える必要があります。 各引数値は、位置対応する仮引数と同じ型に必ず評価されなければなりません。

まとめると、関数呼び出し時は:

  1. 呼び出し元関数の実行が一時停止されます。

  2. 呼び出し先関数returnされるまで実行されます。

  3. 呼び出し元関数の実行が再開されます。

呼び出し先関数は次のようにreturnされます:

詳細な手順は:

  1. 関数呼び出しの引数値が評価されます。 評価順は左から右です。

  2. 呼び出し元関数の実行が一時停止されます。 すべての関数スコープ変数および定数は現在の値を保持します。

  3. 呼び出し先がユーザー定義の場合、 呼び出し先関数の関数スコープ変数ごとにメモリが割り当てられます。

  4. 呼び出し先関数の仮引数には、位置で一致する関数呼び出しの引数値が割り当てられます。 例えば、呼び出し先関数の最初の仮引数は、呼び出し元の最初の引数値となります。

  5. 呼び出し先関数へ制御が移ります。 ユーザー定義関数の場合、本体の最初の文から実行されます。

  6. 呼び出し先関数はreturnされるまで実行されます。

  7. 制御が呼び出し元関数に戻り、呼び出し先の実行が解除されます。 戻り値を持つ場合、その値が関数呼び出し式の値となります。

関数呼び出しの位置は、呼び出し位置と呼ばれます。これは、トークンのうち call_phrase構文規則の解析インスタンスで最初のものの位置です。 呼び出し位置は動的コンテキストの一種です。 そのため、同じテキスト上の位置が複数の呼び出し位置となることもあります。

注: フラグメントシェーダー内の関数呼び出しが、クアッド内の全ての呼び出しが discardされた場合、 returnしない可能性があります。 この場合、制御は呼び出し元関数に戻りません。

11.3. const関数

const属性付きで宣言された関数は、 シェーダー生成時に評価できます。 これらの関数は定数関数と呼ばれます。 これらへの呼び出しは定数式の一部として利用できます。

関数内に定数式でない 式やconst宣言でない宣言が含まれている場合、 シェーダー生成エラーとなります。

注: const属性は ユーザー定義関数には付けられません。

例:定数関数
const first_one = firstLeadingBit(1234 + 4567); // 12に評価される
                                                // first_oneの型はi32、
                                                // firstLeadingBitはAbstractIntに対応しないため
@id(1) override x : i32;
override y = firstLeadingBit(x); // 定数式は
                                 // override式でも利用可能
                                 // firstLeadingBit(x)はこの文脈では定数式ではない

fn foo() {
  var a : array<i32, firstLeadingBit(257)>; // 定数関数は
                                            // パラメータがすべて定数式なら
                                            // 定数式内で利用可能
}

11.4. 関数に対する制約

注: 再帰はどの宣言種にも循環が許可されていないため禁止されています。

例:有効・無効なポインター引数
fn bar(p : ptr<function, f32>) {
}

fn baz(p : ptr<private, i32>) {
}

fn bar2(p : ptr<function, f32>) {
  let a = &*&*(p);

  bar(p); // 有効
  bar(a); // 有効
}

fn baz2(p : ptr<storage, f32>) {
}

struct S {
  x : i32
}

@group(0) @binding(0)
var<storage> ro_storage : f32;
@group(0) @binding(1)
var<storage, read_write> rw_storage : f32;

var usable_priv : i32;
var unusable_priv : array<i32, 4>;
fn foo() {
  var usable_func : f32;
  var unusable_func : S;
  var i32_func : i32;

  let a_priv = &usable_priv;
  let b_priv = a_priv;
  let c_priv = &*&usable_priv;
  let d_priv = &(unusable_priv.x);
  let e_priv = d_priv;

  let a_func = &usable_func;
  let b_func = &unusable_func;
  let c_func = &(*b_func)[0];
  let d_func = c_func;
  let e_func = &*a_func;

  baz(&usable_priv); // 有効、変数のアドレス取得
  baz(a_priv);       // 有効、実質的に変数のアドレス取得
  baz(b_priv);       // 有効、実質的に変数のアドレス取得
  baz(c_priv);       // 有効、実質的に変数のアドレス取得
  baz(d_priv);       // 有効、メモリビューが変化
  baz(e_priv);       // 有効、メモリビューが変化
  baz(&i32_func);    // 無効、アドレス空間不一致

  bar(&usable_func); // 有効、変数のアドレス取得
  bar(c_func);       // 有効、メモリビューが変化
  bar(d_func);       // 有効、メモリビューが変化
  bar(e_func);       // 有効、実質的に変数のアドレス取得

  baz2(&ro_storage); // 有効、変数のアドレス取得
  baz2(&rw_storage); // 無効、アクセスモード不一致
}

11.4.1. エイリアス解析

11.4.1.1. ルート識別子

メモリ位置は、関数の実行中にメモリビューを使ってアクセスできます。 関数内では、各メモリビューに特定のルート識別子が存在し、 その関数内で最初にそのメモリへのアクセスを提供する変数または仮引数の名前となります。

関数内で参照型ポインター型の局所的な式は、 あるルート識別子のための新しい名前を導入することがありますが、 各式には静的に決定可能なルート識別子があります。

Eポインター型または参照型の場合、 ルート識別子は 以下のように見つかる元の変数ポインター型の仮引数です:

11.4.1.2. 別名化(エイリアシング)

元の変数は、 ルート識別子に対する動的な概念であり、 関数の呼び出し位置に依存しますが、 WGSLモジュールは静的解析によって、各ルート識別子に対する全ての可能な元の変数の集合を決定できます。

2つのルート識別子が 同じ元の変数であれば、 それらは別名(エイリアス)となります。 WGSL関数の実行は、1つが書き込みで、もう1つが読み込みまたは書き込みとなる 別名化されたルート識別子を介してメモリにアクセスする可能性がある場合、 絶対に許可されません。 これは、呼び出しグラフの葉から上方向(すなわちトポロジカル順)に解析することで判定されます。 各関数に対し、以下の集合を記録します:

関数の各呼び出し位置において、 以下のいずれかが起きる場合はシェーダー生成エラーとなります:

例:エイリアス解析
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とのインターフェース指定など、様々な目的で使用されます。

一般的に、言語的観点からは、型チェックや意味解析の際に属性は無視できます。 また、属性名はコンテキスト依存名であり、 属性のパラメータの一部もコンテキスト依存名です。

attribute :

'@' ident_pattern_token argument_expression_list ?

| align_attr

| binding_attr

| blend_src_attr

| builtin_attr

| const_attr

| diagnostic_attr

| group_attr

| id_attr

| interpolate_attr

| invariant_attr

| location_attr

| must_use_attr

| size_attr

| workgroup_size_attr

| vertex_attr

| fragment_attr

| compute_attr

属性の説明で明示的に許可されていない限り、属性は同じオブジェクトまたは型に複数回指定してはなりません

12.1. align

align_attr :

'@' 'align' '(' expression ',' ? ')'

align 属性
説明 構造体メンバーのメモリ上の配置を制約します。

必ず構造体型のメンバーにのみ付与してください。

この属性は、囲んでいる構造体型の値がメモリ上でどのように配置されるかに影響します。 構造体自体およびその構成メンバーのバイトアドレスを制約します。

align(n)S のメンバーに型 T で適用され、 S がアドレス空間 AS の変数の store type になり得る場合、 ここで ASuniform でないならば、 n満たさなければならない
n = k × RequiredAlignOf(T,AS) ただし、k は正の整数。

アラインメントとサイズの規則は相互再帰的です。 しかし、上記の制約は、ネストされた型の必要なアラインメントに依存するため、明確に定義されています。 型には有限のネスト深度があるためです。

§ 14.4 メモリレイアウト参照。

パラメータ 必須const-expressionであり、解決される型はi32またはu32であること。
必須は正の値であること。
必須は2のべき乗であること。

12.2. binding

binding_attr :

'@' 'binding' '(' expression ',' ? ')'

binding 属性
説明 バインドgroup内のリソースのバインディング番号を指定します。 § 13.3.2 リソースインターフェース参照。

必ずリソース変数にのみ付与してください。

パラメータ 必須const-expressionであり、解決される型はi32またはu32であること。
必須は0以上であること。

12.3. blend_src

blend_src_attr :

'@' 'blend_src' '(' expression ',' ? ')'

blend_src 属性
説明 dual_source_blending機能が有効な場合、 フラグメント出力の一部を指定します。 § 13.3.1.3 入出力ロケーション参照。

必ず 構造体型の location属性が付与されたメンバーにのみ適用してください。 必ず 数値スカラー型または数値ベクトル型の オブジェクト宣言にのみ適用してください。 絶対に シェーダーステージ入力に含めてはなりません。 絶対に シェーダーステージ出力に含めてはなりませんが、 フラグメントシェーダーステージは例外です。

パラメータ 必ず定数式であり、i32またはu32(値は0または1)に解決されなければなりません。

12.4. builtin

builtin_attr :

'@' 'builtin' '(' builtin_value_name ',' ? ')'

builtin 属性
説明 対象オブジェクトが指定されたトークンにより示される組み込み値であることを指定します。 § 13.3.1.1 組み込み入出力参照。

必ずエントリーポイント関数のパラメータ、エントリーポイントの戻り値型、または構造体のメンバーにのみ適用してください。

パラメータ 必ず 組み込み値名トークン組み込み値用)でなければなりません。

12.5. const

const_attr :

'@' 'const'

const 属性
説明 関数が定数関数として使用できることを指定します。 この属性は絶対にユーザー定義関数には付与できません。

必ず関数宣言にのみ適用してください。

注: この属性は、どの組み込み関数が定数式で使用可能かを記述するための記法です。

パラメータ なし

12.6. diagnostic

diagnostic_attr :

'@' 'diagnostic' diagnostic_control

diagnostic_control :

'(' severity_control_name ',' diagnostic_rule_name ',' ? ')'

diagnostic 属性
説明 範囲診断フィルターを指定します。§ 2.3 診断参照。

同じ構文要素に複数のdiagnostic属性を指定可能ですが、 必ず異なるトリガールールを指定してください。

パラメータ 1番目のパラメータはseverity_control_nameです。

2番目のパラメータはdiagnostic_rule_nameトークンであり、 トリガールールを指定します。

12.7. group

group_attr :

'@' 'group' '(' expression ',' ? ')'

group 属性
説明 リソースのバインディンググループを指定します。 § 13.3.2 リソースインターフェース参照。

必ずリソース変数にのみ適用してください。

パラメータ 必ず定数式であり、i32またはu32に解決されなければなりません。
必ず負でない値であること。

12.8. id

id_attr :

'@' 'id' '(' expression ',' ? ')'

id 属性
説明 パイプライン上書き可能定数に対して、 数値識別子を別名として指定します。

必ず override宣言スカラー型にのみ適用してください。

パラメータ 必ず定数式であり、i32またはu32に解決されなければなりません。
必ず負でない値であること。

12.9. interpolate

interpolate_attr :

'@' 'interpolate' '(' interpolate_type_name ',' ? ')'

| '@' 'interpolate' '(' interpolate_type_name ',' interpolate_sampling_name ',' ? ')'

interpolate_type_name :

ident_pattern_token

interpolate 属性
説明 ユーザー定義IOの補間方法を指定します。 この属性はユーザー定義頂点出力およびフラグメント入力でのみ重要です。 § 13.3.1.4 補間参照。

必ずlocation属性が付与された宣言にのみ適用してください。

パラメータ 1番目のパラメータは必ず 補間型名トークン補間型用)でなければなりません。

2番目のパラメータ(存在する場合)は必ず 補間サンプリング名トークン補間サンプリング用)でなければなりません。

12.10. invariant

invariant_attr :

'@' 'invariant'

invariant 属性
説明 頂点シェーダーのposition組み込み出力値に適用すると、 結果の計算は異なるプログラムや同じエントリーポイントの異なる呼び出し間で不変となります。 すなわち、2つのエントリーポイントでposition出力のデータと制御フローが一致する場合、 結果値も必ず一致します。 position組み込み入力値には効果はありません。

必ずposition組み込み値のみに適用してください。

注: この属性はHLSLのprecise修飾子、 GLSLのinvariant修飾子に対応します。

パラメータ なし

12.11. location

location_attr :

'@' 'location' '(' expression ',' ? ')'

location 属性
説明 エントリーポイントのユーザー定義IOの一部を指定します。 § 13.3.1.3 入出力ロケーション参照。

必ずエントリーポイント関数のパラメータ、エントリーポイント戻り値型、 または構造体型のメンバーにのみ適用してください。 必ず数値スカラー型または数値ベクトル型の オブジェクト宣言にのみ適用してください。 絶対にcompute シェーダーステージ入力には含めてはなりません。

パラメータ 必ず定数式であり、i32またはu32に解決されなければなりません。
必ず負でない値であること。

12.12. must_use

must_use_attr :

'@' 'must_use'

must_use 属性
説明 この関数への呼び出しとして使用しなければなりません。 つまり、この関数への呼び出しが関数呼び出し文全体となってはなりません

必ず戻り値型を持つ関数宣言にのみ適用してください。

注: 多くの関数は値を返し副作用がありません。 そのような関数を関数呼び出し文としてのみ呼び出すのはプログラミング上の欠陥となる場合があります。 この性質を持つ組み込み関数は@must_useとして宣言されています。 ユーザー定義関数にも@must_use属性を付与できます。

注: @must_use規則を意図的に回避したい場合は、 ダミー代入や関数呼び出しを初期化子とする 値宣言を使用してください。

パラメータ なし

12.13. size

size_attr :

'@' 'size' '(' expression ',' ? ')'

size 属性
説明 構造体メンバーに予約されるバイト数を指定します。

この数値は、そのメンバーの型のバイトサイズ以上でなければなりません

size(n)が型Tのメンバーに付与された場合、 SizeOf(T) ≤ n

§ 14.4 メモリレイアウト参照。

必ず構造体型のメンバーにのみ適用してください。 メンバー型は固定フットプリントを持つ必要があります

パラメータ 必ず定数式であり、i32またはu32に解決されなければなりません。
必ず正の値であること。

12.14. workgroup_size

workgroup_size_attr :

'@' 'workgroup_size' '(' expression ',' ? ')'

| '@' 'workgroup_size' '(' expression ',' expression ',' ? ')'

| '@' 'workgroup_size' '(' expression ',' expression ',' expression ',' ? ')'

workgroup_size 属性
説明 コンピュートシェーダーのworkgroup gridのx, y, z次元を指定します。

1番目のパラメータはx次元を指定します。 2番目のパラメータがあればy次元を指定し、無い場合は1とみなします。 3番目のパラメータがあればz次元を指定し、無い場合は1とみなします。

必須コンピュートシェーダーのエントリポイント関数にのみ適用されること。 してはならないは他のオブジェクトに適用されてはならないこと。

パラメータ 1個~3個のパラメータを取ります。

各パラメータは定数式またはoverride式でなければなりません。 すべてのパラメータはi32u32で統一してください。

定数式が0以下であればシェーダー生成エラーです。

パイプライン生成エラーは、 指定パラメータが0以下やWebGPU APIの上限値を超える場合、 またはパラメータ値の積がAPIの上限値を超える場合に発生します (WebGPU § 3.6.2 上限値参照)。

12.15. シェーダーステージ属性

以下のシェーダーステージ属性は 特定のシェーダーステージエントリポイント関数として 関数を指定します。 これらの属性は関数宣言にのみ 適用しなければならず、 一つの関数に対して同時に複数付与することはできません。 パラメータは取りません。

12.15.1. vertex

vertex_attr :

'@' 'vertex'

vertex属性は、関数を バーテックスシェーダーステージエントリポイントとして レンダーパイプラインに宣言します。

12.15.2. fragment

fragment_attr :

'@' 'fragment'

fragment属性は、関数を フラグメントシェーダーステージエントリポイントとして レンダーパイプラインに宣言します。

12.15.3. compute

compute_attr :

'@' 'compute'

compute属性は、関数を コンピュートシェーダーステージエントリポイントとして コンピュートパイプラインに宣言します。

13. エントリポイント

エントリポイントは、特定のシェーダーステージで処理を行うユーザー定義関数です。

13.1. シェーダーステージ

WebGPUはGPUに対して描画ディスパッチコマンドの形で作業を発行します。 これらのコマンドは、シェーダーステージの入力出力、および 接続されたリソースのコンテキストでパイプラインを実行します。

パイプラインは、GPU上で実行される作業を、いくつかのステージのシーケンスとして記述します。その中にはプログラム可能なステージも含まれます。 WebGPUでは、描画やディスパッチコマンドを実行する前にパイプラインを作成します。 パイプラインには2種類あります: GPUComputePipeline と GPURenderPipeline。

ディスパッチコマンドは、 GPUComputePipeline を使用して、 コンピュートシェーダーステージ を論理的なグリッド上の多数のポイントで並列性を制御しながら実行し、 バッファーやイメージリソースを読み込み、必要に応じて更新します。

描画コマンドは、 GPURenderPipelineを使って、 他の固定機能ステージの間に2つのプログラム可能なステージを含むマルチステージプロセスを実行します:

WebGPU仕様ではパイプラインについてさらに詳しく記述されています。

WGSLは、パイプラインのプログラム可能な部分に対応する3つのシェーダーステージを定義しています:

各シェーダーステージは、それぞれ独自の機能と制約を持ちます(詳細は他の箇所に記載)。

13.2. エントリポイント宣言

エントリポイントを作成するには、シェーダーステージ属性付きのユーザー定義関数を宣言します。

WebGPU APIでパイプラインを構成する際、 エントリポイントの関数名はWebGPUのGPUProgrammableStage オブジェクトのentryPoint属性にマッピングされます。

エントリポイントの形式的なパラメータは、そのステージのシェーダーステージ入力を示します。 エントリポイントの戻り値(指定される場合)は、そのステージのシェーダーステージ出力を示します。

各形式的パラメータの型およびエントリポイントの戻り値の型は、以下のいずれかでなければなりません:

構造体型は、ユーザー定義入力同士や、必要に応じて組み込み入力とグループ化するために使用できます。 また、構造体型を戻り値の型として使用することで、ユーザー定義出力同士や、必要に応じて組み込み出力とグループ化できます。

注: bool型はユーザー定義入力/出力には使用できません。 front_facing組み込み値にのみ許可されています。

注: コンピュートエントリポイントは戻り値の型を持ちません。

例: エントリポイント
@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では、エントリポイント宣言に適用できる以下の属性が定義されています:

例: workgroup_size 属性
@compute @workgroup_size(8,4,1)
fn sorter() { }

@compute @workgroup_size(8u)
fn reverser() { }

// パイプラインで上書き可能な定数の使用例
@id(42) override block_width = 12u;
@compute @workgroup_size(block_width)
fn shuffler() { }

// エラー: workgroup_size は compute シェーダーで指定する必要があります
@compute
fn bad_shader() { }

13.3. シェーダーインターフェース

シェーダーインターフェースは、シェーダーステージ外部のデータへアクセスするため、 読み書きやシェーダーの設定に用いる パイプライン上書き可能 定数を含むオブジェクト群です。 このインターフェースには以下が含まれます:

宣言 D がシェーダーによって静的アクセスされるのは次の場合です:

注:静的アクセスは再帰的に定義され、以下の点を考慮します:

ここで、シェーダーのインターフェースを次の構成要素で厳密に定義できます:

13.3.1. ステージ間の入力・出力インターフェース

シェーダーステージ入力 は、パイプラインの上流からそのステージに渡されるデータです。 各データは 組み込み入力値 か、ユーザー定義入力です。

シェーダーステージ出力 は、パイプラインの下流処理へ渡すためのデータです。 各データは 組み込み出力値 か、ユーザー定義出力です。

IO属性は、 オブジェクトを シェーダーステージ入力シェーダーステージ出力として定義し、 さらに入力や出力のプロパティを記述します。 IO属性は以下です:

13.3.1.1. 組み込み入力・出力

組み込み入力値 は、システム生成の制御情報を取得するためのものです。 エントリポイントは組み込み入力の重複を含んではなりません。

ステージ S の組み込み入力(名前 X、型 TX)は 以下のいずれかの方法でアクセスされます:

  1. パラメータが builtin(X) 属性を持ち、型が TX である。

  2. パラメータの型が構造体で、そのメンバーのいずれかが builtin(X) 属性を持ち、型が TX である。

逆に、エントリポイントのパラメータまたはパラメータのメンバーがbuiltin属性を持つ場合、 対応する組み込み値は必ずそのエントリポイントのシェーダーステージの入力でなければなりません。

組み込み出力値は、 シェーダーが制御情報をパイプラインの後続処理へ渡すためのものです。 エントリポイントは組み込み出力の重複を含んではなりません。

ステージ S の組み込み出力(名前 Y、型 TY)は 以下のいずれかの方法で設定されます:

  1. エントリポイントの 戻り値型builtin(Y) 属性を持ち、型が TY である。

  2. エントリポイントの 戻り値型が構造体型で、 そのメンバーのいずれかが builtin(Y) 属性を持ち、型が TY である。

逆に、エントリポイントの戻り値型または戻り値型のメンバーがbuiltin属性を持つ場合、 対応する組み込み値は必ずそのエントリポイントのシェーダーステージの出力でなければなりません。

注: position 組み込みは、頂点シェーダーの出力であり、フラグメントシェーダーの入力でもあります。

組み込み入力値と組み込み出力値をまとめて、組み込み値と呼びます。

以下の表は利用可能な組み込み値をまとめたものです。 それぞれは 組み込み値名トークンであり、トークンとなります。 詳細は後続セクションで説明します。

組み込み入力・出力値一覧
名前 ステージ 方向 拡張
vertex_index vertex input u32
instance_index vertex input u32
clip_distances vertex output array<f32, N> (N8) 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>
workgroup_id compute input vec3<u32>
num_workgroups compute input vec3<u32>
subgroup_invocation_id compute input u32 subgroups
fragment
subgroup_size compute input u32 subgroups
fragment
例:組み込み値の宣言
 struct VertexOutput {
   @builtin(position) my_pos: vec4<f32>,
   @builtin(clip_distances) my_clip_distances: array<f32, 8>,
 }

 @vertex
 fn vs_main(
   @builtin(vertex_index) my_index: u32,
   @builtin(instance_index) my_inst_index: u32,
 ) -> VertexOutput {}

 struct FragmentOutput {
   @builtin(frag_depth) depth: f32,
   @builtin(sample_mask) mask_out: u32
 }

 @fragment
 fn fs_main(
   @builtin(front_facing) is_front: bool,
   @builtin(position) coord: vec4<f32>,
   @builtin(sample_index) my_sample_index: u32,
   @builtin(sample_mask) mask_in: u32,
 ) -> FragmentOutput {}

 @compute @workgroup_size(64)
 fn cs_main(
   @builtin(local_invocation_id) local_id: vec3<u32>,
   @builtin(local_invocation_index) local_index: u32,
   @builtin(global_invocation_id) global_id: vec3<u32>,
) {}
13.3.1.1.1. clip_distances
名前 clip_distances
ステージ vertex
array<f32, N>
方向 出力
説明 配列の各値はユーザー定義クリップ面への距離を表します。clip distanceが0のとき、その頂点は面上にあり、正の値ならクリップ半空間内、負の値なら半空間外です。clip_distancesの配列サイズは8以下でなければなりません。 詳細は WebGPU § 23.2.4 プリミティブのクリッピング を参照。
13.3.1.1.2. frag_depth
名前 frag_depth
ステージ fragment
f32
方向 出力
説明 ビューポートの深度範囲内で更新されたフラグメントの深度値。

詳細は WebGPU § 3.3 座標系 を参照。

13.3.1.1.3. front_facing
名前 front_facing
ステージ fragment
bool
方向 入力
説明 現在のフラグメントがfront-facingプリミティブ上ならtrue、そうでなければfalseです。
13.3.1.1.4. global_invocation_id
名前 global_invocation_id
ステージ compute
vec3<u32>
方向 入力
説明 現在の呼び出しのglobal invocation ID、つまりコンピュートシェーダーグリッド内での位置です。global_invocation_idの値は workgroup_id × workgroup_size + local_invocation_idと等しいです。
13.3.1.1.5. instance_index
名前 instance_index
ステージ vertex
u32
方向 入力
説明 現在のAPIレベルの描画コマンド内での頂点インスタンス番号。

最初のインスタンスの番号は、描画コマンドのfirstInstance引数に等しく(直接指定でも間接指定でも)、以降はインスタンス毎に1増加します。

13.3.1.1.6. local_invocation_id
名前 local_invocation_id
ステージ compute
vec3<u32>
方向 入力
説明 現在の呼び出しのlocal invocation ID、つまりワークグループグリッド内での位置です。
13.3.1.1.7. local_invocation_index
名前 local_invocation_index
ステージ compute
u32
方向 入力
説明 現在の呼び出しのlocal invocation index、ワークグループグリッド内での呼び出し位置を線形化した値です。
13.3.1.1.8. num_workgroups
名前 num_workgroups
ステージ compute
vec3<u32>
方向 入力
説明 ディスパッチサイズ、すなわちvec3<u32>(group_count_x, group_count_y, group_count_z)であり、APIによってコンピュートシェーダーがディスパッチされたときの値です。
13.3.1.1.9. position
名前 position
ステージ vertex
vec4<f32>
方向 出力
説明 現在の頂点のクリップ位置クリップ空間座標における)。

出力値 (x,y,z,w) WebGPU の 正規化デバイス座標において (x/w, y/w, z/w) にマッピングされます。

WebGPU § 3.3 座標系 および WebGPU § 23.2.4 プリミティブクリッピング を参照してください。

w 座標がゼロの場合、動的エラーが発生します。

名前 position
ステージ fragment
vec4<f32>
方向 入力
説明
現在のフラグメントの入力位置。

fp をフラグメントの入力位置、
rp をそのフラグメントの RasterizationPointvp を描画コマンドに有効な [[viewport]] とします。

このとき、概略的には:

fp.xy = rp.destination.position
fp.z = rp.depth
fp.w = rp.perspectiveDivisor

詳細な説明:

  • fp.x と fp.y は、フレームバッファ内での現在のフラグメントの位置の補間されたx, y座標です。

    フレームバッファは左上が(0.0,0.0)、右下が(vp.width, vp.height)の2次元グリッドです。 各ピクセルはx, y方向それぞれ1.0単位の大きさを持ち、ピクセル中心は整数座標から(0.5,0.5)ずれた位置です。

  • fp.zは現在のフラグメントの補間された深度値です。例:

    • 正規化デバイス座標(ndc)で深度0は fp.z = vp.minDepth へマッピングされます。

    • 正規化デバイス座標で深度1は fp.z = vp.maxDepth へマッピングされます。

  • fp.wはフラグメントの遠近除算値で、1.0 ÷ vertex_wvertex_wは頂点シェーダーのposition出力のw成分)の補間値です。

詳細は WebGPU § 3.3 座標系 および WebGPU § 23.2.5 ラスタライズ を参照。

13.3.1.1.10. primitive_index
名前 primitive_index
ステージ fragment
u32
方向 入力
説明 現在のインスタンスに対して描画操作開始から処理されたプリミティブ数に基づいたプリミティブごとのインデックスです。 0から始まり、各ポイント、ライン、トライアングルプリミティブが処理されるごとに1ずつ増加します。インスタンスごとに0にリセットされます。 プリミティブ再スタート値によるストリッププリミティブの再起動はprimitive_indexに影響しません。このインデックスはプリミティブの全フラグメントで一様です。
13.3.1.1.11. sample_index
名前 sample_index
ステージ fragment
u32
方向 入力
説明 現在のフラグメントのサンプルインデックス。値は最低0で、最大sampleCount-1となります。sampleCountは GPUレンダーパイプラインで指定されたMSAAサンプル count です。 この属性が適用され、フラグメントシェーダーの効果がsample_indexの値で変化する場合、フラグメントシェーダーはサンプルごとに1回呼び出されます。

詳細は WebGPU § 10.3 GPURenderPipeline を参照。

13.3.1.1.12. sample_mask
名前 sample_mask
ステージ fragment
u32
方向 入力
説明 現在のフラグメントのサンプルカバレッジマスク。このビットマスクには、レンダリング中のプリミティブによってカバーされているサンプルが示されます。

詳細は WebGPU § 23.2.11 サンプルマスキング を参照。

名前 sample_mask
ステージ fragment
u32
方向 出力
説明 現在のフラグメントのサンプルカバレッジマスク制御。この変数に最後に書き込まれた値がシェーダー出力マスクとなります。値のゼロビットは対応するカラーバッファのサンプルを捨てます。

詳細は WebGPU § 23.2.11 サンプルマスキング を参照。

13.3.1.1.13. vertex_index
名前 vertex_index
ステージ vertex
u32
方向 入力
説明 現在のAPIレベルの描画コマンド内での頂点のインデックス(描画インスタンスに依存しない)。

非インデックス描画の場合、最初の頂点のインデックスは描画コマンドのfirstVertex引数に等しく(直接指定でも間接指定でも)、以降は頂点毎に1増加します。

インデックス付き描画の場合、インデックスは頂点に対するインデックスバッファのエントリ+描画コマンドのbaseVertex引数(直接指定でも間接指定でも)です。

13.3.1.1.14. workgroup_id
名前 workgroup_id
ステージ compute
vec3<u32>
方向 入力
説明 現在の呼び出しのworkgroup ID、すなわちコンピュートシェーダーグリッド全体の中でのワークグループの位置です。

同じワークグループ内の全呼び出しは同じworkgroup IDを持ちます。

ワークグループIDは(0,0,0)から(group_count_x - 1, group_count_y - 1, group_count_z - 1)まで広がります。

13.3.1.1.15. subgroup_invocation_id
名前 subgroup_invocation_id
ステージ compute または fragment
u32
方向 入力
説明 現在の呼び出しのsubgroup invocation IDです。

IDは[0, subgroup_size - 1]の範囲内です。

13.3.1.1.16. subgroup_size
名前 subgroup_size
ステージ compute または fragment
u32
方向 入力
説明 現在の呼び出しのサブグループのサイズです。
13.3.1.2. ユーザー定義入力・出力

ユーザー定義データはパイプラインの最初の入力として、ステージ間で、またはパイプラインの最終出力として渡すことができます。

ユーザー定義入力データおよび ユーザー定義出力データ必須です:

computeシェーダーはユーザー定義入力・出力を持ってはなりません

13.3.1.3. 入出力ロケーション

各入出力ロケーションは最大16バイトの値を格納できます。 型のバイトサイズは§ 14.4.1 アラインメントとサイズSizeOf列で定義されています。 例えば、4要素の浮動小数点ベクトルは1つのロケーションを占有します。

IOロケーションはlocation属性で指定します。

各ユーザー定義入力および出力必ず明示的に指定されたIOロケーションを持たなければなりません。 エントリポイントIOの各構造体メンバーは必ず組み込み値(§ 13.3.1.1 組み込み入力・出力参照)か、ロケーションが割り当てられている必要があります。

WGSLモジュール内で定義された各エントリポイントについて、inputsをそのシェーダーステージ入力(すなわち形式パラメータや、構造体型の形式パラメータのメンバーのロケーション)集合とする。
WGSLモジュールで定義された各構造体型S(シェーダーステージ入力・出力に使われていなくても)について、 membersSlocation属性を持つメンバー集合とする。

注:ロケーション番号は入力と出力で別々です: エントリポイントのシェーダーステージ入力用ロケーション番号は、出力用ロケーション番号と競合しません。

注:エントリポイントの出力内でロケーションが重複しないように追加ルールは必要ありません。 出力が構造体の場合、上記の最初のルールによって重複が防止されます。 それ以外の場合、出力はスカラーまたはベクトルであり、単一のロケーションしか割り当てられません。

注:エントリポイントで利用可能なロケーション数はWebGPU APIによって定義されます。

例:location属性の適用
struct A {
  @location(0) x: f32,
  // ロケーションは16バイトだが、xとyは同じロケーションを共有できない
  @location(1) y: f32
}

// in1はロケーション0と1を占有。
// in2はロケーション2を占有。
// 戻り値はロケーション0を占有。
@fragment
fn fragShader(in1: A, @location(2) in2: f32) -> @location(0) vec4<f32> {
 // ...
}

ユーザー定義IOは同じ構造体内で組み込み値と混在できます。例えば、

例:組み込み値とユーザー定義IOの混在
// 組み込み値とユーザー定義入力の混在
struct MyInputs {
  @location(0) x: vec4<f32>,
  @builtin(front_facing) y: bool,
  @location(1) @interpolate(flat) z: u32
}

struct MyOutputs {
  @builtin(frag_depth) x: f32,
  @location(0) y: vec4<f32>
}

@fragment
fn fragShader(in1: MyInputs) -> MyOutputs {
  // ...
}
例:無効なロケーション割り当て
struct A {
  @location(0) x: f32,
  // 無効:xとyは同じロケーションを共有できない
  @location(0) y: f32
}

struct B {
  @location(0) x: f32
}

struct C {
  // 無効:ユーザー定義IOを持つ構造体はネスト不可
  b: B
}

struct D {
  x: vec4<f32>
}

@fragment
// 無効:構造体型にロケーションは適用不可
fn fragShader1(@location(0) in1: D) {
  // ...
}

@fragment
// 無効:in1とin2は同じロケーションを共有できない
fn fragShader2(@location(0) in1: f32, @location(0) in2: f32) {
  // ...
}

@fragment
// 無効:構造体へのロケーションの適用不可
fn fragShader3(@location(0) in1: vec4<f32>) -> @location(0) D {
  // ...
}
13.3.1.4. 補間

著者はinterpolate属性の利用によってユーザー定義IOデータの補間方法を制御できます。 WGSLは補間のタイプと補間のサンプリングの2つの側面を制御できます。

補間タイプ必ず次のいずれかの補間タイプ名トークンでなければなりません:

perspective

値は遠近法的に正しく補間されます。

linear

値は線形(遠近法補正なし)で補間されます。

flat

値は補間されません。

補間サンプリング必ず次のいずれかの補間サンプリング名トークンでなければなりません:

center

補間はピクセルの中心で行われます。

centroid

補間は、現在のプリミティブ内でフラグメントがカバーしている全サンプル内にある点で行われます。 この値はプリミティブ内の全サンプルで同じとなります。

sample

補間はサンプルごとに行われます。 この属性が適用されるとフラグメントシェーダーはサンプルごとに1回呼び出されます。

first

値はプリミティブの最初の頂点から提供されます。

either

値はプリミティブの最初または最後の頂点から提供されます。どちらから提供されるかは実装依存です。

スカラーまたはベクトル浮動小数点型のユーザー定義IOについて:

スカラーまたはベクトル整数型のユーザー定義頂点出力およびフラグメント入力は必ず補間タイプflatで指定しなければなりません。

ステージ間インターフェースの検証は、レンダーパイプライン内で 各ユーザー定義フラグメント入力の補間プロパティが同じlocationを割り当てた頂点出力の補間プロパティと一致するかをチェックします。 一致しない場合、パイプライン生成エラー発生します

13.3.2. リソースインターフェース

リソースは、シェーダーステージ外部のデータにアクセスするためのオブジェクトであり、 オーバーライド宣言シェーダーステージ入力・出力ではありません。 リソースはシェーダーの全呼び出しで共有されます。

リソースには4種類あります:

シェーダーのリソースインターフェース静的アクセスされるモジュールスコープの リソース変数の集合です。 シェーダーステージの関数によってアクセスされます。

各リソース変数は必ずgroupbinding属性を持って宣言しなければなりません。 これらはシェーダーステージと組み合わせて、シェーダーのパイプライン上のリソースのバインドアドレスを特定します。 詳細はWebGPU § 8.3 GPUPipelineLayoutを参照。

同じシェーダー内の2つの異なるリソース変数は 必ず groupbinding値のペアを共有してはなりません。

13.3.3. リソースレイアウトの互換性

WebGPUは、シェーダーのリソースインターフェースが使用しているパイプラインのレイアウトと一致することを要求します。

WGSLのリソースインターフェース内の変数が、互換性のないWebGPU binding member または binding type にバインドされている場合、これはパイプライン作成エラーとなります。互換性は以下の表で定義されています。

WebGPUバインディングタイプの互換性
WGSLリソース WebGPU binding member WebGPU binding type
uniform buffer buffer GPUBufferBindingType "uniform"
storage bufferread_write アクセス) "storage"
storage bufferread アクセス) "read-only-storage"
sampler sampler GPUSamplerBindingType "filtering"
"non-filtering"
sampler_comparison "comparison"
sampled texturedepth texturemultisampled texture texture GPUTextureSampleType "float"
"unfilterable-float"
"sint"
"uint"
"depth"
write-only storage texture storageTexture GPUStorageTextureAccess "write-only"
read-write storage texture "read-write"
read-only storage texture "read-only"
external texture externalTexture (該当なし)

WebGPU API 現行標準仕様にてインターフェースの検証要件を参照してください。

13.3.4. バッファバインディングによる実行時サイズ配列の要素数決定

storage buffer 変数に実行時サイズの配列が含まれている場合、その配列の要素数は対応するresourceのサイズから決定されます。

詳細として、型RATの実行時サイズ配列に対するNRuntimeは:

truncate((EBBS − array_offset) ÷ array_stride)、ここで

シェーダーはNRuntimeを、arrayLength組み込み関数を使って計算できます。

注: このアルゴリズムは曖昧さがありません。 実行時サイズ配列がより大きな型の一部である場合、それは構造体の最後のメンバーとしてのみ現れることができ、 その構造体自体が他の配列や構造体の要素になることはできません。

NRuntimeは対応するバッファバインディングのサイズにより決定され、 これはdraw またはdispatch commandごとに異なる場合があります。

WebGPUの検証規則により、1 ≤ NRuntimeが保証されます。

次のコード例では:
例:単純な実行時サイズ配列の要素数
@group(0) @binding(1) var<storage> weights: array<f32>;

次の表は、対応する実効バッファバインディングサイズに基づく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 )
次のコード例では:
例:複雑な実行時サイズ配列の要素数
struct PointLight {                          //             align(16) size(32)
  position : vec3f,                          // offset(0)   align(16) size(12)
  // -- implicit member alignment padding -- // offset(12)            size(4)
  color : vec3f,                             // offset(16)  align(16) size(12)
  // -- implicit struct size padding --      // offset(28)            size(4)
}

struct LightStorage {                        //             align(16)
  pointCount : u32,                          // offset(0)   align(4)  size(4)
  // -- implicit member alignment padding -- // offset(4)             size(12)
  point : array<PointLight>,                 // offset(16)  align(16) elementsize(32)
}

@group(0) @binding(1) var<storage> lights : LightStorage;

以下の表は、lights変数のpointメンバーに対するNRuntimeの例を示します。

複雑な実行時サイズ配列の要素数例
実効バッファバインディングサイズ lights変数のpointメンバーのNRuntime 計算方法
1024 31 truncate( ( 1024 - 16 ) ÷ 32) )
1025 31 truncate( ( 1025 - 16 ) ÷ 32) )
1039 31 truncate( ( 1039 - 16 ) ÷ 32) )
1040 32 truncate( ( 1040 - 16 ) ÷ 32) )

14. メモリ

WGSLでは、storable型の値はメモリに格納でき、後で取得することができます。 このセクションでは、メモリの構造と、メモリにアクセスする操作の意味論について説明します。 メモリに格納できる値の型や、メモリアクセスに使用される型については§ 6.4 メモリビューを参照してください。

14.1. メモリロケーション

メモリは一連の個別なメモリロケーションから構成されます。 各メモリロケーションは8ビットのサイズです。 メモリに影響を与える操作は、1つ以上のメモリロケーションの集合とやりとりします。 合成型に対するメモリ操作はパディングされたメモリロケーションをアクセスしません。 そのため、操作によってアクセスされるメモリロケーションの集合は連続していない場合があります。

2つのメモリロケーションの集合は、そのメモリロケーションの集合の交差が空でない場合、オーバーラップします。

14.2. メモリアクセスモード

メモリアクセスは、 メモリロケーションに作用する操作です。

1つの操作で、読み取り・書き込み、または両方を行うことができます。

特定のメモリロケーションは、メモリのアクセスモードとして表現される、特定の種類のアクセスのみをサポートする場合があります。

アクセスモード
アクセスモード サポートされるアクセス
read 読み取りアクセスのみサポート、書き込み不可。
write 書き込みアクセスのみサポート、読み取り不可。
read_write 読み取り・書き込み両方のアクセスをサポート。

WGSLは事前宣言された列挙子としてreadwriteread_writeを持ちます。

14.3. アドレス空間

メモリロケーションはアドレス空間で分割されています。 各アドレス空間は、 可変性・可視性・格納できる値・変数の使用方法など独自の特性を持ちます。 詳細は§ 7 変数と値の宣言を参照してください。

特定のメモリビューのアクセスモードは、しばしば文脈によって決まります:

storageアドレス空間は readおよび read_writeアクセスモードの両方をサポートします。 他のアドレス空間は1つのアクセスモードのみをサポートします。 各アドレス空間のデフォルトアクセスモードは以下の表で説明されています。

アドレス空間
アドレス空間 呼び出し間の共有 デフォルトアクセスモード 備考
function 同じ呼び出しのみ read_write
private 同じ呼び出しのみ read_write
workgroup 同じコンピュートシェーダーワークグループ内の呼び出し read_write 最外層の配列の要素数パイプラインオーバーライド可能定数にできる。
uniform 同じシェーダーステージの呼び出し read uniform buffer変数用
storage 同じシェーダーステージの呼び出し read storage buffer変数用
handle 同じシェーダーステージの呼び出し read samplerおよびtexture変数用

WGSLは各アドレス空間に対して事前宣言された列挙子を持ちますが、handleアドレス空間にはありません。

workgroupアドレス空間内の変数は、必ず静的にアクセスされるように、コンピュートシェーダーステージでのみ使用できます。

storageアドレス空間(storage buffer)の変数は、アクセスモードがreadの場合のみ頂点シェーダーステージから静的にアクセスできます。 ストア型storage textureかつ writeまたはread_writeアクセスモードの場合は 頂点シェーダーステージから静的アクセスできません。 詳細はWebGPU createBindGroupLayout()を参照。

注: 各アドレス空間は異なるパフォーマンス特性を持つ場合があります。

WGSLソースで変数宣言ポインター型を書く場合:

14.4. メモリレイアウト

WGSLにおける型のレイアウトは、アドレス空間とは独立しています。 しかし厳密に言えば、そのレイアウトはホスト共有可能バッファによってのみ観察できます。 Uniform bufferstorage buffer変数は、 メモリ上でバイト列として組織された大量データを共有するために使用されます。 バッファはCPUとGPU間、あるいはパイプライン内の異なるシェーダーステージ間、または異なるパイプライン間で共有されます。

バッファデータは再フォーマットや変換なしで共有されるため、バッファの生成者と利用者がメモリレイアウト(バッファ内のバイトがWGSLの型付き値にどのように構成されるかの記述)に合意していない場合、 動的エラーとなります。 これらのバイトは、共通の基準位置からの値のメモリロケーションです。

バッファ変数のストア型必須ホスト共有可能であり、以下で説明する完全なメモリレイアウトが必要です。

各バッファ変数は必須で、 uniformまたは storageアドレス空間で宣言されなければなりません。

型のメモリレイアウトは、次の場合にのみ意味を持ちます:

8ビットバイトはホスト共有可能メモリの最も基本的な単位です。 このセクションで定義される用語は、8ビットバイトの数を示します。

以下の記法を用います。ここで Tホスト共有可能または固定フットプリント型、 Sはホスト共有可能または固定フットプリント構造体型、 Aはホスト共有可能または固定フットプリント配列か実行時サイズ配列です:

14.4.1. アライメントとサイズ

ホスト共有可能または固定フットプリントデータ型 Tにはアライメントとサイズがあります。

アライメントとは、その型の値が メモリ上のどこに配置できるかを制約する整数であり、 型のアライメントは必須で 値の開始メモリロケーションのバイトアドレスを割り切る必要があります。 アライメントは値に対するより効率的なハードウェア命令の利用や、 特定のアドレス空間で要求される厳しいハードウェア要件の充足に役立ちます。(アドレス空間レイアウト制約参照)

注: 各アライメント値は必ず2の冪です。

バイトサイズとは、型や構造体メンバーの値を格納するために ホスト共有可能メモリ内で予約される連続バイト数です。 サイズには型末尾の非アドレス可能なパディングが含まれる場合があります。 そのため、値のロードやストアはサイズより少ないメモリロケーションをアクセスすることがあります。

ホスト共有可能および固定フットプリント型のアライメントとサイズは、以下の表で再帰的に定義されます:

ホスト共有可能・固定フットプリント型のアライメントとサイズ
ホスト共有可能または固定フットプリント型 T AlignOf(T) SizeOf(T)
bool
参照。
4 4
i32u32、またはf32 4 4
f16 2 2
atomic<T> 4 4
vec2<T>(Tbooli32u32、またはf328 8
vec2<f16> 4 4
vec3<T>(Tbooli32u32、 またはf3216 12
vec3<f16> 8 6
vec4<T>(Tbooli32u32、 またはf3216 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...MNmax(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の実行時決定要素数
注: 多くのGPUは、単一バイトの書き込みをデータレースなしで実装できません。 bool値が4バイトで4バイトアライメントを占有することを規定することで、 実装はメモリ上で隣接するbool値をデータレースなしでサポートできます。

14.4.2. 構造体メンバーのレイアウト

構造体の内部レイアウトは、そのメンバーのサイズとアライメントから算出されます。 デフォルトでは、メンバーは重複なく順番に、メンバーのアライメント要件を満たしつつ密に配置されます。

このデフォルトの内部レイアウトは、レイアウト属性で上書きできます。属性は次の通りです:

構造体型Sの第iメンバーには、 SizeOfMember(S, i)とAlignOfMember(S, i)で表されるサイズとアライメントがあります。 メンバーのサイズとアライメントは、§ 14.4.4 値の内部レイアウトに記載の通り、 構造体の開始位置から各メンバーのバイトオフセットを計算するために使われます。

SizeOfMember(S, i)は、第iメンバーにsize(k)属性が指定されていればkです。 それ以外の場合は、メンバー型Tに対するSizeOf(T)です。
AlignOfMember(S, i)は、第iメンバーにalign(k)属性が指定されていればkです。 それ以外の場合は、メンバー型Tに対するAlignOf(T)です。

構造体メンバーにsize属性が指定されている場合、 その値はメンバー型のサイズ以上である必要があります

SizeOfMember(S, i) ≥ SizeOf(T)
ここでTSの第iメンバーの型です。

構造体の最初のメンバーは必ず開始位置からバイトオフセット0となります:

OffsetOfMember(S, 1) = 0

以降の各メンバーは、型のアライメントを満たし、前メンバーと重複しない最小のオフセット位置に配置されます。 各メンバーインデックスi > 1の場合:

OffsetOfMember(S, i) = roundUp(AlignOfMember(S, i ), OffsetOfMember(S, i-1) + SizeOfMember(S, i-1))
例:暗黙のメンバーサイズとアライメントによる構造体レイアウト
struct A {                                     //             align(8)  size(24)
    u: f32,                                    // offset(0)   align(4)  size(4)
    v: f32,                                    // offset(4)   align(4)  size(4)
    w: vec2<f32>,                              // offset(8)   align(8)  size(8)
    x: f32                                     // offset(16)  align(4)  size(4)
    // -- implicit struct size padding --      // offset(20)            size(4)
}

struct B {                                     //             align(16) size(160)
    a: vec2<f32>,                              // offset(0)   align(8)  size(8)
    // -- implicit member alignment padding -- // offset(8)             size(8)
    b: vec3<f32>,                              // offset(16)  align(16) size(12)
    c: f32,                                    // offset(28)  align(4)  size(4)
    d: f32,                                    // offset(32)  align(4)  size(4)
    // -- implicit member alignment padding -- // offset(36)            size(4)
    e: A,                                      // offset(40)  align(8)  size(24)
    f: vec3<f32>,                              // offset(64)  align(16) size(12)
    // -- implicit member alignment padding -- // offset(76)            size(4)
    g: array<A, 3>,    // element stride 24       offset(80)  align(8)  size(72)
    h: i32                                     // offset(152) align(4)  size(4)
    // -- implicit struct size padding --      // offset(156)           size(4)
}

@group(0) @binding(0)
var<storage,read_write> storage_buffer: B;
例:明示的なメンバーサイズ・アライメントによる構造体レイアウト
struct A {                                     //             align(8)  size(32)
    u: f32,                                    // offset(0)   align(4)  size(4)
    v: f32,                                    // offset(4)   align(4)  size(4)
    w: vec2<f32>,                              // offset(8)   align(8)  size(8)
    @size(16) x: f32                           // offset(16)  align(4)  size(16)
}

struct B {                                     //             align(16) size(208)
    a: vec2<f32>,                              // offset(0)   align(8)  size(8)
    // -- implicit member alignment padding -- // offset(8)             size(8)
    b: vec3<f32>,                              // offset(16)  align(16) size(12)
    c: f32,                                    // offset(28)  align(4)  size(4)
    d: f32,                                    // offset(32)  align(4)  size(4)
    // -- implicit member alignment padding -- // offset(36)            size(12)
    @align(16) e: A,                           // offset(48)  align(16) size(32)
    f: vec3<f32>,                              // offset(80)  align(16) size(12)
    // -- implicit member alignment padding -- // offset(92)            size(4)
    g: array<A, 3>,    // element stride 32       offset(96)  align(8)  size(96)
    h: i32                                     // offset(192) align(4)  size(4)
    // -- implicit struct size padding --      // offset(196)           size(12)
}

@group(0) @binding(0)
var<uniform> uniform_buffer: B;

14.4.3. 配列レイアウト例

例:固定サイズ配列のレイアウト例
// 配列:
//   - アライメントは4 = AlignOf(f32)
//   - 要素ストライドは4 = roundUp(AlignOf(f32),SizeOf(f32)) = roundUp(4,4)
//   - サイズは32 = stride * number_of_elements = 4 * 8
var small_stride: array<f32, 8>;

// 配列:
//   - アライメントは16 = AlignOf(vec3<f32>) = 16
//   - 要素ストライドは16 = roundUp(AlignOf(vec3<f32>), SizeOf(vec3<f32>))
//                          = roundUp(16,12)
//   - サイズは128 = stride * number_of_elements = 16 * 8
var bigger_stride: array<vec3<f32>, 8>;
例:実行時サイズ配列のレイアウト例
// 配列:
//   - アライメントは4 = AlignOf(f32)
//   - 要素ストライドは4 = roundUp(AlignOf(f32),SizeOf(f32)) = 4
// Bがdrawまたはdispatchコマンドのバインディングにおける実効バッファバインディングサイズの場合、要素数は:
//   N_runtime = floor(B / element stride) = floor(B / 4)
@group(0) @binding(0)
var<storage> weights: array<f32>;

// 配列:
//   - アライメントは16 = AlignOf(vec3<f32>) = 16
//   - 要素ストライドは16 = roundUp(AlignOf(vec3<f32>), SizeOf(vec3<f32>))
//                          = roundUp(16,12)
// Bがdrawまたはdispatchコマンドのバインディングにおける実効バッファバインディングサイズの場合、要素数は:
//   N_runtime = floor(B / element stride) = floor(B / 16)
var<storage> directions: array<vec3<f32>>;

14.4.4. 値の内部レイアウト

この節では、ホスト共有可能値の内部が、全体値の配置を前提としてバッファのバイト位置にどのように配置されるかを説明します。 これらのレイアウトは値の型や、構造体メンバーのalign属性やsize属性に依存します。

値が配置されるバッファのバイトオフセットは型のアライメント要件を満たす必要があります。型Tの値がバッファオフセットkに配置されるとき、k = c × AlignOf(T)(非負整数c)となります。

データはアドレス空間に関係なく同一に現れます。

注: bool型はホスト共有可能型ではありません。 WGSLではbool値のサイズとアライメントを4バイトと規定しますが、内部レイアウトは規定しません。

u32またはi32の値Vがホスト共有バッファのバイトオフセットkに配置された場合:

注: i32は2の補数表現を使うため、符号ビットはビット位置31です。

64ビット整数レイアウト: WebGPU APIの一部機能は64ビット符号なし整数をバッファに書き込みます。この値Vがホスト共有バッファのバイトオフセットkに現れる場合:

注: WGSLには具体的な64ビット整数型はありません。

f32の値VIEEE-754 binary32形式で表現されます。 1ビットの符号、8ビットの指数部、23ビットの仮数部を持ちます。 Vがホスト共有バッファのバイトオフセットkに配置された場合:

f16の値VIEEE-754 binary16形式で表現されます。 1ビットの符号、5ビットの指数部、10ビットの仮数部を持ちます。 Vがホスト共有バッファのバイトオフセットkに配置された場合:

注: 上記の規則により、ホスト共有バッファ内の数値はリトルエンディアン形式で格納されます。

atomic型atomic<T>の値Vがホスト共有バッファに配置される場合、基底型Tの値と同じ内部レイアウトを持ちます。

ベクター型vecN<T>の値Vがホスト共有バッファのバイトオフセットkに配置される場合:

行列型matCxR<T>の値Vがホスト共有バッファのバイトオフセットkに配置される場合:

配列型Aの値がホスト共有メモリバッファのバイトオフセットkに配置される場合:

構造体型Sの値がホスト共有メモリバッファのバイトオフセットkに配置される場合:

14.4.5. アドレス空間レイアウト制約

storageおよびuniformアドレス空間は、 異なるバッファレイアウト制約を持ち、本節で説明します。

address spacesのうちuniform以外は すべてstorageアドレス空間と同じ制約を持ちます。

変数が直接または間接的に参照するすべての構造体・配列型は その変数のアドレス空間の制約を必ず守らなければなりません。 アドレス空間制約に違反するとshader-creation errorとなります。

本節では、RequiredAlignOf(S, C)を アドレス空間Cで使用するホスト共有可能型または固定フットプリント型Sのバイトオフセットアライメント要件と定義します。

アドレス空間Cにおけるホスト共有可能型・固定フットプリント型のアライメント要件
ホスト共有可能または固定フットプリント型SSCに現れると仮定) RequiredAlignOf(S, C)
Cuniformでない場合
RequiredAlignOf(S, C)
Cuniformの場合
booli32u32f32、 または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) 該当なし
struct S AlignOf(S) roundUp(16, AlignOf(S))

Tの構造体メンバーは、構造体開始位置から RequiredAlignOf(T, C)の倍数の バイトオフセットで配置される必要があります

OffsetOfMember(S, i) = k × RequiredAlignOf(T, C)
ここでkは非負整数、構造体Sの第iメンバーの型はT

要素型Tの配列は、アドレス空間Cに対して RequiredAlignOf(T, C)の倍数の 要素ストライドを持つ必要があります

StrideOf(array<T, N>) = k × RequiredAlignOf(T, C)
StrideOf(array<T>) = k × RequiredAlignOf(T, C)
ここでkは正整数

uniformアドレス空間ではさらに:

注: 以下の例は、uniformバッファのレイアウト要件を満たすために 構造体メンバーにalignsize属性を使う方法を示します。 特に、GLSLバッファ(std140レイアウト)をWGSLに機械的に変換する際にこれらの技術が使えます。

例:uniformアドレス空間のオフセット要件を満たす
struct S {
  x: f32
}
struct Invalid {
  a: S,
  b: f32 // invalid: aとbの間のオフセットは4バイトだが、16以上必要
}
@group(0) @binding(0) var<uniform> invalid: Invalid;

struct Valid {
  a: S,
  @align(16) b: f32 // valid: aとbの間のオフセットは16バイト
}
@group(0) @binding(1) var<uniform> valid: Valid;
例:uniformアドレス空間のストライド要件を満たす
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メモリモデルのメモリ書き込み操作に相当します。

読み取りアクセスは、 下記のいずれかを呼び出しが実行したときに発生します:

書き込みアクセスは、 下記のいずれかを呼び出しが実行したときに発生します:

Atomic read-modify-write組み込み関数は 読み取りアクセスと書き込みアクセス両方となる単一のメモリ操作を行います。

読み取り・書き込みアクセスは他の場合に発生しません。 これらはVulkanメモリモデルでメモリ操作と呼ばれます。

メモリ操作は、その操作で使用される特定のメモリビューに関連づけられた メモリロケーション集合のみを正確にアクセスします。 例えば、複数メンバーを持つ構造体のu32をメモリ読み取りする場合、u32メンバーに関連するメモリロケーションのみを読み取ります。

注: ベクターのコンポーネントに対する書き込みアクセスは そのベクターに関連するすべてのメモリロケーションをアクセスする場合があります

例:メモリロケーションへのアクセス
struct S {
  a : f32,
  b : u32,
  c : f32
}

@group(0) @binding(0)
var<storage> v : S;

fn foo() {
  let x = v.b; // v.aやv.cのメモリロケーションはアクセスしない。
}

14.5.2. メモリモデル参照

モジュールスコープのresource変数は、 一意なメモリモデル参照groupbindingのペアごとに形成します。 その他の変数(つまりfunctionprivateworkgroupアドレス空間)は、 変数の存続期間ごとに一意なメモリモデル参照を形成します。

14.5.3. スコープ付き操作

呼び出しがスコープ付き操作を実行する場合、それは1つまたは2つの呼び出し集合に影響します。 これらの集合はメモリスコープと実行スコープです。メモリスコープは、操作によるメモリ内容の更新を観測できる呼び出し集合を指定します。 同期組み込み関数の場合、影響を受ける全てのメモリ操作は、関数より前にプログラム順で行われたものが、 関数より後にプログラム順で行われた操作に可視となります。 実行スコープは、 操作に参加できる呼び出し集合を指定します(§ 15.6 集合操作参照)。

アトミック組み込み関数は、アトミック操作にマッピングされ、そのメモリスコープは次の通りです:

同期組み込み関数は、実行およびメモリスコープWorkgroupの制御バリアにマッピングされます。

暗黙的・明示的な微分は、暗黙的にquad実行スコープを持ちます。

注: 生成されたシェーダーでVulkanメモリモデルが有効化されていない場合は、QueueFamilyの代わりにDeviceスコープを使用します。

14.5.4. メモリ意味論

全てのアトミック組み込み関数Relaxed メモリ意味論を使用し、ストレージクラス意味論はありません。

注: WGSLのアドレス空間はSPIR-Vのストレージクラスに相当します。

workgroupBarrierAcquireReleaseメモリ意味論WorkgroupMemory意味論を使用します。 storageBarrierAcquireReleaseメモリ意味論UniformMemory意味論を使用します。 textureBarrierAcquireReleaseメモリ意味論ImageMemory意味論を使用します。

注: workgroupBarrierstorageBarrierを組み合わせると、AcquireRelease 順序意味論と両方のWorkgroupMemoryUniformMemoryメモリ意味論を使用します。

注: いかなるアトミック・同期組み込み関数もMakeAvailableMakeVisible意味論は使用しません。

14.5.5. privateとnon-private

storageworkgroupアドレス空間における非アトミックな読み取りアクセスはすべて non-privateと見なされ、NonPrivatePointer | MakePointerVisibleメモリオペランドをWorkgroupスコープで持つ読み取り操作に対応します。

storageworkgroupアドレス空間における非アトミックな書き込みアクセスはすべて non-privateと見なされ、NonPrivatePointer | MakePointerAvailableメモリオペランドをWorkgroupスコープで持つ書き込み操作に対応します。

handle アドレス空間における非アトミックな読み取りアクセスnon-privateと見なされ、 NonPrivateTexel | MakeTexelVisibleメモリオペランドをWorkgroupスコープで持つ読み取り操作に対応します。

handle アドレス空間における非アトミックな書き込みアクセスnon-privateと見なされ、 NonPrivateTexel | MakeTexelAvailableメモリオペランドをWorkgroupスコープで持つ書き込み操作に対応します。

15. 実行

§ 1.1 概要では、シェーダーがどのように呼び出され、invocationに分割されるかを説明しています。 このセクションでは、invocationが個別および集合的にどのように実行されるかに関する追加の制約について説明します。

15.1. Invocation内のプログラム順序

WGSLモジュール内の各ステートメントは、実行中に0回以上実行される可能性があります。 特定のinvocationにおいて、あるステートメントの各実行は一意の 動的ステートメントインスタンス を表します。

ステートメントが式を含む場合、ステートメントの意味論は以下を決定します。

式のネストは、評価を完了するために満たす必要があるデータ依存関係を定義します。 すなわち、ネストされた式は、囲っている式を評価する前に評価されなければなりません。 式のオペランドの評価順序はWGSLでは左から右です。 例えば、foo() + bar()では、foo()bar()より先に評価されます。 詳しくは§ 8 式を参照してください。

WGSLモジュール内のステートメントは、制御フロー順に実行されます。 詳しくは§ 9 ステートメントおよび§ 11.2 関数呼び出しを参照してください。

15.2. 一様性

集合的操作 (例えば、バリア、微分、または暗黙的に計算された微分に依存するテクスチャ操作など)は、GPU上で同時に動作する複数のinvocation間の協調が必要です。 この操作は、すべてのinvocationが同時に、つまり一様な制御フローで実行された場合に、正しくかつ移植性を持って動作します。

逆に、invocationの厳密な部分集合のみが操作を実行した場合、すなわち非一様な制御フローで実行された場合、 正しくないまたは移植性のない動作が発生します。 非一様な制御依存は、制御フローステートメントの挙動が非一様な値に依存することで生じます。

例えば、異なるinvocationが ifbreak-ifwhileforの条件で異なる値を計算した場合や、 switchのセレクターで異なる値になった場合、 または短絡評価の二項演算子(&&||)の左オペランドで異なる値になった場合などに非一様な制御依存が生じます。

これらの非一様な値は、多くの場合、静的に一様であると証明されていない特定のソースに遡ることができます。 これらのソースには、以下が含まれますが、これに限定されません:

正しく移植性のある動作を保証するために、WGSLの実装は現行標準に従い、 静的な一様性解析を行い、各集合的操作が一様な制御フローで実行されることを証明しようとします。 以下のサブセクションで解析について説明します。

一様性失敗は、 現行標準に従い、 一様性解析が特定の集合的操作一様な制御フローで実行されることを証明できない場合に発生します。

15.2.1. 用語と概念

以下の定義は参考情報であり、次のサブセクションで解析が計算する内容の直感を与えるものです。 実際には解析こそが、これらの概念やプログラムの妥当性、一様性規則の破れを定義します。

あるinvocationグループについて:

15.2.2. 一様性解析の概要

以下のサブセクションでは、集合的操作一様な制御フローでのみ実行されることを静的解析で検証する方法を規定します。

この解析は動的エラーが発生しないことを前提としています。 動的エラーが発生するシェーダーステージは、たとえ一様性解析の結果がどうであれ、すでに移植性がありません。

注記:この解析は以下の望ましい特性を持ちます:

各関数は2つのことを満たすように解析されます:

一様性失敗は、この2つのチェックのいずれかが失敗した場合に発生します。

この解析の一部として、各関数について、その呼び出し元の解析を助けるためのメタデータを計算します。 つまり、まず呼び出しグラフを構築し、標準ライブラリ以外の関数を呼ばない関数(葉)からエントリーポイントに向かって順に解析します。 こうすることで、関数を解析する時点で、その呼び出し先全てのメタデータがすでに計算されていることが保証されます。 言語仕様上、再帰は禁止されているため、サイクルに陥る心配はありません。

注記:これは言い換えれば、関数を「(間接的に)呼び出し先である」部分順序でトポロジカルソートし、その順序で解析するということです。

さらに、各関数呼び出しについて、解析はその呼び出しが一様な制御フローであることを証明できなかった場合に発生する発生規則の集合を計算・伝播します。 これを呼び出しの潜在的発生セットと呼びます。 このセットの要素は以下のいずれかです:

15.2.3. 関数の均一性要件の分析

各関数は2つの段階で分析されます。

最初の段階では、関数の構文をたどりながら、以下の小節に記載された規則に従って有向グラフを構築します。 第2段階ではそのグラフを探索し、この関数の呼び出しに関する制約を計算し、 必要に応じて均一性失敗を引き起こすことがあります。

注:4つの特別なノード RequiredToBeUniform.error, RequiredToBeUniform.warning, RequiredToBeUniform.info, および MayBeNonUniform 以外の各ノードは、 以下のステートメントの真偽値を捉えていると理解できます:

エッジは、ソースノードに対応するステートメントからターゲットノードに対応するステートメントへの含意として理解できます。

例えば、workgroupBarrier組み込み関数は均一な制御フロー内でのみ呼び出されなければならないという均一性要件があります。 これを表現するために、RequiredToBeUniform.errorから workgroupBarrier呼び出し箇所に対応するノードへエッジを追加します。 これは、RequiredToBeUniform.errorは命題Trueに対応し、 RequiredToBeUniform.error -> X は Xが真であることを意味します。

逆に、均一性を保証できないもの(例えばスレッドIDを保持する変数など)については、対応するノードからMayBeNonUniformノードへエッジを追加します。 これを理解する方法として、MayBeNonUniformは命題Falseに対応し、X -> MayBeNonUniform は Xが偽であることを意味します。

この解釈の結果、RequiredToBeUniform.errorから到達可能なすべてのノードは、 プログラムが有効であるために均一である必要があるものに対応し、MayBeNonUniformから到達可能なすべてのノードは、 均一性を保証できないものに対応します。 従って、RequiredToBeUniform.errorからMayBeNonUniformへの経路が存在する場合、 均一性違反が発生し、均一性失敗が発生します。

RequiredToBeUniform.warningおよびRequiredToBeUniform.infoノードも同様に使われますが、 これらは警告情報診断を出すべき場合を判定するのに使われます:

§ 2.3 診断で説明されているように、より重大度の高い診断が生成されている場合、低い重大度の診断は破棄されることがあります。

各関数について、2つのタグが計算されます:

形式パラメータごとに、1つまたは2つのタグが計算されます:

呼び出し箇所タグの値
呼び出し箇所タグ 説明
CallSiteRequiredToBeUniform.S,
ここで S は次のいずれかの重大度: error, warning, info
関数は均一な制御フローからのみ呼び出さなければなりません。 そうでない場合、重大度Sの診断が発生します。

potential-trigger-setと関連付けられています。

CallSiteNoRestriction 関数は非均一な制御フローから呼び出すことができます。
関数タグの値
関数タグ 説明
ReturnValueMayBeNonUniform 関数の戻り値は非均一である可能性があります。
NoRestriction 関数は非均一性を導入しません。
パラメータタグの値
パラメータタグ 説明
ParameterRequiredToBeUniform.S,
ここで S は次のいずれかの重大度: error, warning, info
パラメータは均一な値でなければなりません。 パラメータ型がポインタの場合、メモリビュー自体(その内容は必ずしも含まない)は均一でなければなりません。 そうでない場合、重大度Sの診断が発生します。

potential-trigger-setと関連付けられています。

ParameterContentsRequiredToBeUniform.S,
ここで S は次のいずれかの重大度: error, warning, info
ポインタパラメータが指すメモリに格納された値は均一な値でなければなりません。 そうでない場合、重大度Sの診断が発生します。

potential-trigger-setと関連付けられています。

ParameterNoRestriction パラメータ値には均一性要件はありません。
パラメータ戻り値タグの値
パラメータ戻り値タグ 説明
ParameterReturnContentsRequiredToBeUniform 関数の戻り値が均一な値となるためには、パラメータは均一な値でなければなりません。 パラメータがポインタの場合、ポインタが指すメモリの値も均一でなければなりません。
ParameterReturnNoRestriction パラメータ値には均一性要件はありません。
ポインタパラメータタグの値
ポインタパラメータタグ 説明
PointerParameterMayBeNonUniform ポインタパラメータが指すメモリの値は、関数呼び出し後に非均一になる可能性があります。
PointerParameterNoRestriction ポインタパラメータが指すメモリの値の均一性は関数呼び出しによって影響を受けません。

以下のアルゴリズムは、与えられた関数についてこれらのタグを計算する方法を説明します:

注: この時点でグラフ全体は破棄可能です。 上記のタグだけが、この関数の呼び出し元を分析するために記憶しておくべき情報です。 しかし、グラフにはより有益な診断を提供するための情報が含まれています。 例えば、ある関数内の値が均一であることを証明できない場合、 それが他の関数で均一性失敗を引き起こす原因となります。 有益な診断では、その非均一な値と、診断の発生箇所となる関数呼び出しも記述されます。

15.2.4. ポインタのデシュガー処理

関数アドレス空間内のポインタ型の各パラメータは、 パラメータをデリファレンスした値と同等の初期値を持つローカル変数宣言としてデシュガーされます。 つまり、関数アドレス空間のポインタはローカル変数宣言のエイリアスとして扱われます。 初期値の代入は、i番目のパラメータに対するparam_i_contentsノードへのエッジを生成します(すなわち、V(e)param_i_contentsです)。

let宣言 Lで、 effective-value-typeポインタ型の場合、次のようにデシュガーされます:

このデシュガー処理により、ポインタのroot識別子を各使用箇所で直接露出させ、後続の解析を簡素化します。

注: 均一性解析の目的では、型チェックはこのデシュガー前後の両方で行われるものとします。

例:均一性解析におけるポインタ
fn foo(p : ptr<function, array<f32, 4>>, i : i32) -> f32 {
  let p1 = p;
  var x = i;
  let p2 = &((*p1)[x]);
  x = 0;
  *p2 = 5;
  return (*p1)[x];
}

// 均一性解析用に変換した foo の等価バージョン
fn foo_for_analysis(p : ptr<function, array<f32, 4>>, i : i32) -> f32 {
  var p_var = *p;            // p 用の変数を導入
  let p1 = &p_var;           // p1用に変数を使用
  var x = i;
  let x_tmp1 = x;            // xの値をキャプチャ
  let p2 = &(p_var[x_tmp1]); // p1の初期化式を置換
  x = 0;
  *(&(p_var[x_tmp1])) = 5;   // p2の初期化式を置換
  return (*(&p_var))[x];     // p1の初期化式を置換
}

15.2.5. 関数スコープ変数の値解析

特定の文における関数スコープ変数の値は、 その変数に到達する代入と、場合によっては初期値で解析できます。

代入は、次のいずれかの条件を満たす場合完全代入です:

それ以外の代入は部分代入です。

参照型の式で、以下のいずれかの場合完全参照です:

ポインタ型の式で、以下のいずれかの場合完全ポインタです:

注: この解析の目的では、ポインタ型の形式パラメータが完全ポインタとなる場合は不要です。

完全参照および同じく完全ポインタは、 該当する元変数xのすべてのメモリ位置のメモリビューです。

完全参照でない参照は部分参照です。 部分参照は次のいずれかです:

注: 部分参照でも、完全参照と同じメモリ位置をカバーできます。 これは、格納型がメンバー1つの構造体や、要素数1の配列型の場合に発生します。

メンバーが1つの構造体型と、その型を格納する変数を考えます:

struct S { member: i32; }
fn foo () {
   var v: S;
}

この場合、vは完全参照、v.memberは部分参照です。 両者のメモリビューは同じ位置をカバーしますが、vの格納型はSv.sの格納型はi32です。

要素数1の配列でも同様の状況が発生します:

fn foo () {
   var arr: array<i32,1>;
}

この場合、arrは完全参照、arr[0]は部分参照です。 両者のメモリビューは同じ位置をカバーしますが、arrの格納型はarray<i32,1>arr[0]の格納型はi32です。

解析を簡素化するため、いかなる種別の部分参照による代入は、 関連する元変数のすべてのメモリ位置を変更しないものとして扱います。 このため解析は保守的となり、実際より多くのプログラムで均一性失敗が発生しうることになります。

完全参照による代入は完全代入です。

部分参照による代入は部分代入です。

後続の節の均一性規則で、RHSValueとして使われる関数スコープ変数の値は、 RHSValue式評価前の変数値を意味します。 LHSValueとして使われる場合は、式が現れる文の実行後の変数値を意味します。

変数への複数の代入は、制御フロー文や部分代入により、その変数の使用箇所に到達する可能性があります。 解析では、制御フロー文から到達する複数の代入を、 各制御フロー出口に到達する代入集合の和集合として結合します。

次の表は、関数スコープ変数への複数の代入の結合規則を示します。 均一性グラフでは、各結合は結果ノードから値の由来ノードへのエッジです。 任意の変数xについて記述します。以下の記号を使います:

関数スコープ変数への複数代入の結合規則
結果 結果からのエッジ
var x; Vin(next) V(0)
var x = e;
Vin(next) V(e)

注: これはxへの完全代入です。

x = e;
r = e;
ここでrは変数xへの完全参照
r = e;
ここでrは変数xへの部分参照
Vout(S) V(e), V(prev)

注: これはxへの部分代入です。

注: 部分代入は前の値も含みます。 代入は格納成分の部分集合のみを書き込むか、書き込まれる値の型が格納型と異なる場合です。

s1 s2
ここでNexts1の動作内にある。

注: s1はしばしばセミコロンで終わります。

Vin(s2) Vout(s1)
if e s1 else s2
ここでNexts1s2の両方の動作にある
Vin(next) Vout(s1), Vout(s2)
if e s1 else s2
ここでNexts1の動作にあるがs2にはない
Vin(next) Vout(s1)
if e s1 else s2
ここでNexts2の動作にあるがs1にはない
Vin(next) Vout(s2)
loop { s1 continuing { s2 } } Vin(s1) Vout(prev), Vout(s2)
loop { s1 continuing { s2 } } Vin(s2) Vout(s1),
Vout(si)
s1内で動作が{Continue}となりs2に制御を移すすべてのsiに対して
loop { s1 continuing { s2 } } Vin(next) Vout(s2),
Vout(si)
s1内で動作が{Break}となりnextに制御を移すすべてのsiに対して
switch e {
case _: s1
case _: s2
...
case _: s3
}
Vin(si) Vout(prev)
switch e {
case _: s1
case _: s2
...
case _: s3
}
Vin(next) Vout(si),
動作がNextまたはBreakを含むすべてのsiに対して,
sj内で動作が{Break}となりnextに制御を移すすべての文についてVout(sj)

その他のすべての文(関数呼び出しを除く)については、Vin(next)はVout(prev)と同値です。

注: デシュガー方法は文の動作分析と同じです。

15.2.6. 文の均一性規則

文の解析規則は、引数として文自体と、その文の冒頭に対応する制御フローのノード(以下「CF」と記述)を受け取り、以下の両方を返します:

下表において、(CF1, S) => CF2 は「S の解析を CF1 の制御フローから開始し、必要なグラフ変更を適用し、結果の制御フローを CF2 と命名する」ことを意味します。 同様に (CF1, E) => (CF2, V) は「CF1 の制御フローから式 E の解析を開始し、必要なグラフ変更を適用し、結果の制御フローノードを CF2、値ノードを V と命名する」ことを意味します(式の解析については次節参照)。 この式の評価は、左辺でない 代入の式に対して使われ、RHSValueと呼ばれます。

また、左辺代入の式に対しても類似の規則があり、それは LHSValue であり、LHSValue: (CF, E) => (CF, L) で表されます。値の均一性に対応するノードではなく、アクセス対象の変数の均一性に対応するノードを算出します。

注: LHSValue には インクリメントデクリメント 文中の式も含まれます。

注: RHSValue には 右辺代入文に含まれる式や、代入・インクリメントデクリメント文に属さない式が含まれます。

複数のエッジを作成する必要がある場合、X -> {Y, Z}X -> Y, X -> Z の省略記法です。

文の均一性規則
新しいノード 再帰的解析 結果の制御フローノード 新しいエッジ
空文 CF
{s} (CF, s) => CF' CF'
s1 s2,
挙動に Next を含む場合

注: s1 はしばしばセミコロンで終わる。

(CF, s1) => CF1
(CF1, s2) => CF2
CF2
s1 s2,
挙動に Next を含まない場合

注: s1 はしばしばセミコロンで終わる。

(CF, s1) => CF1

注: s2 は静的に到達不能であり、再帰的解析しない。 s2 は均一性解析に寄与しない。

CF1
if e s1 else s2
挙動 {Next} の場合
(CF, e) => (CF', V)
(V, s1) => CF1
(V, s2) => CF2
CF
if e s1 else s2
その他の挙動
CFend CFend CFend -> {CF1, CF2}
loop {s1 continuing {s2}}
挙動 {Next} の場合
CF' (CF', s1) => CF1
(CF1, s2) => CF2
CF CF' -> {CF2, CF}
loop {s1 continuing {s2}}
その他の挙動
CF'
loop {s1}
挙動 {Next} の場合
CF' (CF', s1) => CF1 CF CF' -> {CF1, CF}
loop {s1}
その他の挙動
CF'
switch e case _: s_1 .. case _: s_n
挙動 {Next} の場合
(CF, e) => (CF', 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

注: x が function アドレス空間変数の場合、CF値解析においてゼロ値初期化子として使われます。

break;
continue;
break if e; CFend (CF, e) => (CF', V) CFend CFend -> {CF', V}

注: CFend から V へのエッジは、条件値が非均一な場合、この break if 文の結果の制御フローも非均一となることを表します。

return; CF function アドレス空間ポインタ引数 i について、 Value_return_i_contents -> Vin(prev)(§ 15.2.5 関数スコープ変数値解析参照)
return e; (CF, e) => (CF', V) CF' Value_return -> V

function アドレス空間ポインタ引数 i について、 Value_return_i_contents -> Vin(prev)(§ 15.2.5 関数スコープ変数値解析参照)

e1 = e2; LHSValue: (CF, e1) => (CF1, LV)
(CF1, e2) => (CF2, RV)
CF2 LV -> RV

注: LV値解析の結果値です。

_ = e (CF, e) => (CF', V) CF'
let x = e; (CF, e) => (CF', V) CF'
var x = e; (CF, e) => (CF', V) CF'

注: x が function アドレス空間変数の場合、 V値解析の結果値として使われます。

f()
引数なし関数呼び出し文
関数呼び出し解析を実行: (CF, f()) => (CF_after, Result) CF_after
f(e1,...,eN)
引数あり関数呼び出し文
関数呼び出し解析を実行: (CF, f(e1,...,eN)) => (CF_after, Result) CF_after

この解析の目的のため:

パフォーマンスを最大限に高めるため、実装では 非均一な制御フロー の数を減らす工夫がよく行われます。 ただし、呼び出しが均一とみなせるポイントは、様々な要因によって異なります。WGSLの静的解析では、挙動が {Next} である場合、ifswitch、および loop 文の末尾で均一な制御フローに戻ると保守的に仮定します。 このことは、前表において結果の制御フローノードが入力ノードと同じになることで表現されています。

15.2.7. 関数呼び出しの均一性規則

最も複雑な規則は関数呼び出しに関するものです:

注: Vout(call)の定義については§ 15.2.5 関数スコープ変数値分析を参照。

ほとんどの組み込み関数は以下のタグを持ちます:

例外リストは以下の通りです:

注: WGSLの実装では、関数呼び出し前の制御フローが均一であれば、関数呼び出し後も均一であることが保証されます。

15.2.8. 式の均一性規則

式の分析規則は、式自体と、その開始時の制御フローに対応するノード(以下「CF」と記載)を引数として受け取り、以下を返します:

RHSValue 式の均一性規則
新しいノード 再帰的解析 結果の制御フローノード・値ノード 新しいエッジ
e1 || e2 (CF, e1) => (CF1, V1)
(V1, e2) => (CF2, V2)
CF, V2
e1 && e2
リテラル CF, CF
identifier resolving to 関数スコープ変数 "x" で、 識別子が root identifier として memory viewMVE に現れ、load ruleMVE に対して 型チェック中に呼ばれる場合 Result X はこの式を含む文の入力時点での "x" の値に対応するノード CF, Result Result -> {CF, X}

注: X は "x" の Vout(prev) と同等
§ 15.2.5 関数スコープ変数値解析参照)

identifier resolving to 関数スコープ変数 "x" で、 "x" がデシュガーされたポインタパラメータ i であり、 識別子が root identifier として memory viewMVE に現れ、load ruleMVE に対して 型チェック中に呼ばれない場合 CF, param_i
identifier resolving to 関数スコープ変数 "x" で、 識別子が root identifier として memory viewMVE に現れ、load ruleMVE に対して 型チェック中に呼ばれない場合 CF, CF
identifier resolving to const-declarationoverride-declarationlet-declaration、または非組み込みの 形式パラメータ非ポインタ型 "x" Result X は "x" に対応するノード CF, Result Result -> {CF, X}
identifier resolving to 形式パラメータポインタ型かつ storageworkgroupprivate アドレス空間で 非read-only アクセスモードかつ 識別子が root identifier として memory viewMVE に現れ、 load ruleMVE に対して 型チェック中に呼ばれる場合 CF, MayBeNonUniform
identifier resolving to 形式パラメータポインタ型かつ storageworkgroupprivate アドレス空間で 非read-only アクセスモードかつ 識別子が root identifier として memory viewMVE に現れ、 load ruleMVE に対して 型チェック中に呼ばれない場合 CF, CF
identifier resolving to 形式パラメータポインタ型かつ function 以外の アドレス空間で read-only アクセスモードの場合 CF, CF
identifier resolving to 均一な組み込み値 "x" CF, CF
identifier resolving to 非均一な組み込み値 "x" CF,
MayBeNonUniform
identifier resolving to 読み取り専用なモジュールスコープ変数 "x" CF, CF
identifier resolving to 非読み取り専用なモジュールスコープ 変数 "x" で、識別子が root identifier として memory viewMVE に現れ、load ruleMVE に対して 型チェック中に呼ばれる場合 CF,
MayBeNonUniform
identifier resolving to 非読み取り専用なモジュールスコープ 変数 "x" で、識別子が root identifier として memory viewMVE に現れ、load ruleMVE に対して 型チェック中に呼ばれない場合 CF,CF
( e ) (CF, e) => (CF', V) CF', V
op e,
op が単項演算子の場合
e.field
e1 op e2,
op が短絡しない二項演算子の場合
Result (CF, e1) => (CF1, V1)
(CF1, e2) => (CF2, V2)
CF2, Result Result -> {V1, V2}
e1[e2]
f()
引数なし関数呼び出し式
関数呼び出し解析を実行:
(CF, f()) => (CF_after, Result)
CF_after, Result
f(e1,...,eN)
引数あり関数呼び出し式
関数呼び出し解析を実行: (CF, f(e1,...,eN)) => (CF_after, Result) CF_after, Result

以下の組込み入力変数は均一とみなされます:

その他のもの(組込み値参照)は非均一とみなされます。

注: 著者は、均一な組込み値とその他の非均一な入力をまとめて扱うことを避けるべきです。分析ではコンポーネント型の複合型の各要素を個別には分析しません。

LHSValue式の均一性規則
新ノード 再帰分析 結果の制御フローノード・変数ノード 新しいエッジ
identifier function-scope変数"x"に解決 Result Xはこの式を含む文の出力時の"x"の値に対応するノード CF, Result Result -> {CF, X}

注: Xは"x"に対するVin(next)と同値
§ 15.2.5 関数スコープ変数値分析参照)

identifier const宣言、override宣言、let宣言、形式パラメータ"x"に解決 Xは"x"に対応するノード CF, X
identifier モジュールスコープ変数"x"に解決 CF,
MayBeNonUniform
e.field LHSValue: (CF, e) => (CF1, L1) CF1, L1
*e
&e
e1[e2] LHSValue: (CF, e1) => (CF1, L1)
(CF1, e2) => (CF2, V2)
CF2, L1 L1 -> V2

15.2.9. 全ての制御フローポイントの均一性を注釈する

この小節全体は規範的ではありません。

もし実装者が、シェーダー全体の制御フローの各ポイントについて、それが均一かどうか(つまり均一性を要求する関数をそこから呼び出しても有効かどうか)を開発者に診断モードとして表示したい場合は、以下を推奨します:

この到達可能性解析で訪問されなかったノードは、解析によって均一性が証明できる(つまり、そこで導関数等の関数呼び出しが安全である)ことになります。

注: コール時にどのエッジをグラフに追加すべきかを把握するため、ボトムアップ解析も依然として必要です。

15.2.10.

次の例で使用されるグラフは、ノードに対して以下の表記法を用います:

15.2.10.1. 無効な textureSample 関数呼び出し

この例はtextureSample組込み関数呼び出しの無効な使用例を示します。 この関数呼び出しは、条件が非均一値(組込み値position)に依存するif文の中で行われています。 無効な依存チェーンは赤色で強調されています。

例:WGSL 無効な textureSample
@group(0) @binding(0) var t : texture_2d<f32>;
@group(0) @binding(1) var s : sampler;

@fragment
fn main(@builtin(position) pos : vec4<f32>) {
  if (pos.x < 0.5) {
    // 無効な textureSample 関数呼び出し。
    _ = textureSample(t, s, pos.xy);
  }
}
均一性グラフ

この例はまた、if文の後の制御フローの均一性がif文の前と同じであることも示しています(CF_returnがCF_startに接続されている)。 つまり、エントリーポイントの開始時に制御フローが均一であることが保証されているため、if文の後も再び制御フローが均一になります。 textureSample関数呼び出しがif文の外に移動されていれば、このプログラムは有効だったでしょう。 また、if文の条件が均一値(例えば各呼び出しが同じ値をuniform bufferから読み取る等)であれば、このプログラムも有効です。

15.2.10.2. 関数スコープ変数の均一性

この例は、関数スコープ変数の値に依存するbarrier関数呼び出しの有効・無効両方のケースを示します。 workgroupBarrierは、xの値が可変なモジュールスコープ変数aから導出されるため無効です。 storageBarrierは、xの値が不変なモジュールスコープ変数bから導出されるため有効です。 この例は値分析が関数スコープ変数のライフタイム内の異なる均一性期間を分離できることを強調しています。 また、最初のif文の終了後、制御フローが再び均一になることも明示されています。 これは、グラフのその部分が2つ目のif文とは独立しているため分かります。

例:WGSL 関数変数の利用
@group(0) @binding(0) var<storage, read_write> a : i32;
@group(0) @binding(1) var<uniform> b : i32;

@compute @workgroup_size(16,1,1)
fn main() {
  var x : i32;
  x = a;
  if x > 0 {
    // 無効な barrier 関数呼び出し。
    workgroupBarrier();
  }
  x = b;
  if x < 0 {
    // 有効な barrier 関数呼び出し。
    storageBarrier();
  }
}
均一性グラフ

注: サブグラフは理解しやすくするために例として含まれています。

15.2.10.3. 複合値分析の制限

均一性分析の制約の一つは、コンポーネント合成値の個々で独立して追跡しないことです。 つまり、非均一なコンポーネント値がある場合、 分析は合成値全体を非均一として扱います。 この例はこの問題と、シェーダー作者がこの制約を回避するために利用できる潜在的な方法を示しています。

例:無効な複合値 WGSL
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への経路がないことから分かります。

例:有効な代替WGSL
@compute @workgroup_size(16,1,1)
fn main(@builtin(workgroup_id) wgid : vec3<u32>,
        @builtin(local_invocation_index) lid : u32) {
  // 均一性分析はこの比較が常に均一であることを正しく判定できます。
  if wgid.x == 1 {
    // 有効な barrier 関数呼び出し。
    workgroupBarrier();
  }
}
有効な代替均一性グラフ
15.2.10.4. ループ内の均一性

この例では、ループ内で無効なworkgroupBarrier関数呼び出しが行われています。 非均一な組込み値local_invocation_indexが最終的な原因であり、これはbarrierの後に登場していますが、その事実に関わらず無効です。 これは、後のイテレーションでワークグループ内の一部の呼び出しがループを早期に抜ける一方、他の呼び出しがbarrierを実行しようとするために起こります。 解析では、ループ本体の開始時の制御(CF_loop_body)がループ本体終了時の制御(CF_after_if)に依存するエッジとして、イテレーション間の依存関係がモデル化されています。

例:ループ均一性 WGSL
@compute @workgroup_size(16,1,1)
fn main(@builtin(local_invocation_index) lid : u32) {
  for (var i = 0u; i < 10; i++) {
    workgroupBarrier();
    if (lid + i) > 7 {
      break;
    }
  }
}
均一性グラフ
15.2.10.5. ユーザー定義関数呼び出し

この例は最初の例を修正したもので、ユーザー定義の関数呼び出しを使用します。 解析では、scaleの両方のパラメータにparameter return tagとして ParameterReturnContentsRequiredToBeUniformが設定されます。 これにより、main内でscale関数呼び出しの戻り値とposition組込み値の間にパスができます。 このパスは、RequiredToBeUniform.SからMayBeNonUniformへの全体の無効なパスの部分パスです。

例:ユーザー定義関数呼び出し均一性 WGSL
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);
  }
}
scaleの均一性グラフ
mainの均一性グラフ

注: サブグラフは理解しやすくするために例として含まれています。

15.3. コンピュートシェーダーとワークグループ

ワークグループは、 コンピュートシェーダーステージエントリーポイントを同時に実行する一連の呼び出しであり、 workgroupアドレス空間のシェーダー変数へのアクセスを共有します。

コンピュートシェーダーのワークグループグリッドは、 整数座標(i,j,k)の点の集合で、以下を満たします:

ここで、(workgroup_size_x, workgroup_size_y, workgroup_size_z)は エントリーポイントのworkgroup_size属性で指定された値です。

ワークグループグリッドの各点に対して、ワークグループには正確に1つの呼び出しが存在します。

呼び出しのローカル呼び出しIDは、 対応するワークグループグリッド点の座標三つ組(i, j, k)です。

呼び出しがローカル呼び出しIDを持つ場合、 そのローカル呼び出しインデックス

i + (j * workgroup_size_x) + (k * workgroup_size_x * workgroup_size_y)

ワークグループにW個の呼び出しがある場合、 各呼び出しIはユニークなローカル呼び出しインデックスL(I)を持ち、 0 ≤ L(I) < Wを満たし、この範囲全体がカバーされます。

コンピュートシェーダーは、WebGPU実装がディスパッチコマンドをキューから取り出し、指定された作業をGPU上で開始した時に実行が始まります。 ディスパッチコマンドはディスパッチサイズを指定します。 これは整数三つ組(group_count_x, group_count_y, group_count_z)であり、 実行されるワークグループ数を示します(詳細は後述)。

特定のディスパッチのコンピュートシェーダーグリッドは、 整数座標(CSi,CSj,CSk)の点の集合で、以下を満たします:

ここでworkgroup_size_xworkgroup_size_yworkgroup_size_zは、上記のコンピュートシェーダーエントリーポイントで指定された値です。

コンピュートシェーダーのディスパッチで行う作業は、コンピュートシェーダーグリッドの各点に対してエントリーポイントを正確に1回呼び出すことです。

呼び出しのグローバル呼び出しIDは、 対応するコンピュートシェーダーグリッド点の座標三つ組です。

呼び出しはワークグループに編成されており、各呼び出しの グローバル呼び出しID (CSi, CSj, CSk)は 以下で識別される単一のワークグループにマップされます:ワークグループID:

( ⌊ CSi ÷ workgroup_size_x ⌋, ⌊ CSj ÷ workgroup_size_y ⌋, ⌊ CSk ÷ workgroup_size_z ⌋)

さらに、そのワークグループ内の単一の呼び出しは、ローカル呼び出しIDで識別されます:

( CSi mod workgroup_size_x , CSj mod workgroup_size_y , CSk mod workgroup_size_z )

注: ワークグループIDは(0,0,0)から(group_count_x - 1, group_count_y - 1, group_count_z - 1)までの範囲です。

WebGPUでは以下について何も保証しません:

15.4. フラグメントシェーダーとヘルパー呼び出し

フラグメントシェーダーステージの呼び出しは、XおよびY次元で隣接する位置を持つ2x2グリッドに分割されます。 これらのグリッドはクアッドと呼ばれます。 クアッドは一部の集団演算で協調することができます(§ 15.6.2 微分参照)。 呼び出しのクアッド呼び出しIDは、クアッド内で一意のIDであり、以下のとおりです:

注: クアッドID用の組込み値アクセサは存在しません。

通常、フラグメント処理は、RasterizationPointごとにフラグメントシェーダーの呼び出しを1つ生成します(ラスタライズ参照)。 グラフィックスプリミティブの端などでは、クアッドを完全に埋めるだけのRasterizationPointが不足する場合があります。 クアッドに対応するRasterizationPointが1つ、2つ、または3つしかない場合、フラグメント処理はヘルパー呼び出し をそのクアッドの空いている位置ごとに生成します。

ヘルパー呼び出しは、微分の算出を助ける以外に可観測な効果はありません。 そのため、ヘルパー呼び出しには以下の制約が課されます:

クアッド内のすべての呼び出しがヘルパー呼び出しとなった場合(例:discard文の実行による)、 クアッドの実行は終了されることがありますが、そのような終了は非均一な制御フローを生成するものとはみなされません。

15.5. サブグループ

サブグループは、 コンピュートまたはフラグメントシェーダーステージのエントリーポイントを同時に実行し、 データを効率的に共有し集団的に結果を計算できる呼び出しの集合です。 コンピュートまたはフラグメントシェーダーの各呼び出しは正確に1つのサブグループに属します。 コンピュートシェーダーでは、各サブグループは特定のワークグループの部分集合です。 フラグメントシェーダーでは、サブグループは複数の描画コマンドから呼び出しを含む場合があります。 各クアッドは単一のサブグループに含まれます。

サブグループサイズは、 サブグループ内の最大呼び出し数です。 シェーダー内では、subgroup_size組込み値で参照できます。 サブグループサイズは、ディスパッチコマンドおよびワークグループ内で均一な値ですが、描画コマンド内では均一値でない場合があります。 全てのサブグループサイズは[4, 128]の範囲内の2のべき乗であり、特定のデバイス向けにコンパイルされたシェーダーの値はsubgroupMinSizeから subgroupMaxSizeまでの範囲となります(WebGPU § 4.3 GPUAdapter参照)。 実際のサイズはシェーダー、デバイス特性、デバイスコンパイラに依存します。 各デバイスは可能なサブグループサイズ範囲の部分集合(1つだけの場合もある)をサポートします。 デバイスコンパイラは様々なヒューリスティクスで対応サイズから選択します。 サブグループ内の呼び出し数が報告されたサブグループサイズより少ない場合(例:起動数がサブグループサイズ未満)、サブグループはそれより少ない呼び出し数となることがあります。

呼び出しのサブグループ呼び出しIDは、サブグループ内で一意なIDです。 このIDはsubgroup_invocation_id組込み値で参照でき、範囲は[0, subgroup_size - 1]です。 subgroup_invocation_idlocal_invocation_indexの間に定義された関係はありません。 非移植的なコードを避けるため、シェーダー作者はこれら2つの値の特定のマッピングを仮定すべきではありません。

同じサブグループ内の呼び出しが異なる制御フローパスを実行するとき、サブグループ実行が分岐した(diverge)と言います。 これは非均一な制御フローの特別なケースです。 分岐はサブグループ操作の意味に影響します。 サブグループ操作を同時に実行するサブグループ内の呼び出しは、その操作に対してアクティブです。 サブグループ内のその他の呼び出しは、その操作に対して非アクティブです。 サブグループサイズがサブグループ内の呼び出し数を超える場合、余分な仮想呼び出しは非アクティブとみなされます。 ヘルパー呼び出しは操作に対してアクティブにも非アクティブにもなり得ます。 つまり、デバイスによってはヘルパー呼び出しがサブグループ操作に参加する場合もあれば、しない場合もあります。

注: 非均一な制御フローで動作する場合、基盤デバイス間で非移植性が大きく、デバイスコンパイラはこのようなコードを積極的に最適化することが多いです。 その結果、サブグループにはシェーダー作者が想定したものと異なるアクティブ呼び出し集合が含まれる場合があります。

15.6. 集団演算

15.6.1. バリア

バリアはプログラム内のメモリ操作の順序を制御する同期組み込み関数です。 制御バリアは、同じワークグループ内のすべての呼び出しによって、あたかも同時に実行されるかのように実行されます。 このため、制御バリアはコンピュートシェーダーの一様な制御フローでのみ実行しなければなりません

15.6.2. 微分

偏微分は、ある軸方向の値の変化率です。 同じクアッド内のフラグメントシェーダー呼び出しが協調して近似的な偏微分を計算します。

微分を計算する組込み関数は以下です:

フラグメント座標の偏微分は、以下の組込み関数の動作の一部として暗黙的に計算されます:

これらの場合、微分結果はサンプリングされるテクセルのミップレベルを決定したり、textureSampleCompareの場合はサンプリング値を参照値と比較する際に使われます。

呼び出し指定値の偏微分は、§ 17.6 微分組込み関数で説明される組込み関数によって計算されます:

隣接する呼び出しが協調して微分を計算するため、これらの関数はフラグメントシェーダー内で均一な制御フローでのみ呼び出すべきです。 これらの関数を呼び出すたびに、derivative_uniformity診断が、均一性解析で呼び出しが均一な制御フローであることが証明できない場合に発生します。

これらの関数が非均一な制御フローで呼び出された場合、結果は不定値となります。

注: 微分は暗黙のクアッド演算の一種です。 利用にはsubgroups拡張は不要です。

15.6.3. サブグループ演算

サブグループ組込み関数により、サブグループ内の呼び出し間で効率的な通信と計算が可能となります。 サブグループ演算はSIMT(single-instruction multiple-thread)演算です。

アクティブな呼び出しがサブグループ内で通信し、結果を決定します。 そのため、これらの関数は全呼び出しがアクティブなとき(すなわちサブグループレベルの均一な制御フローで)呼び出すと可搬性が最大化されます。

15.6.4. クアッド演算

クアッド組込み関数は、クアッド呼び出しに対して作用します。 これらはクアッド間のデータ通信に有用です。

アクティブな呼び出しがクアッド内で通信し、結果を決定します。 そのため、これらの関数は全呼び出しがアクティブなとき(すなわちクアッドレベルの均一な制御フローで)呼び出すと可搬性が最大化されます。

15.7. 浮動小数点数の評価

WGSL の浮動小数点機能は IEEE-754 標準を基にしていますが、GPU における妥協点を反映して機能が削減されており、移植性を高める追加のガードレールも設けられています。

15.7.1. IEEE-754 の概要

WGSL の浮動小数点型は IEEE-754 のバイナリ浮動小数点型に基づいています。

IEEE-754 バイナリ浮動小数点型は、拡張実数の数直線を次のように近似します:

有限範囲 とは、浮動小数点型の 区間 [low, high] であり、low がその型で最も小さい有限値、high が最も大きい有限値です。

注目すべき IEEE-754 の浮動小数点型は次の通りです:

次のアルゴリズムは、浮動小数点値のビット表現を対応する 拡張実数値または NaN に対応付けます:

アルゴリズム: ビットの浮動小数点解釈

入力: Bits は、バイナリ浮動小数点型の値のビット表現。

出力: FBits で表される浮動小数点値。

手順:

浮動小数点演算の 定義域 とは、演算がよく定義される 拡張実数 の入力集合です。

丸めは、拡張実数x を浮動小数点型の値 x' に対応付けます。 x が浮動小数点型の値である場合、丸めは x をそのまま x' に写します:x = x'x が型の 有限範囲 の外側にある場合、丸めはオーバーフローを引き起こします。 それ以外の場合、x'x より大きい最も小さい浮動小数点値、あるいは x より小さい最大の浮動小数点値となります; どちらが選ばれるかは 丸めモード によって決まります。

一般に、NaN の入力を持つ演算は NaN を返します。 例外として:

IEEE-754 では5種類の 例外が定義されています:

15.7.2. IEEE-754 との相違点

WGSL は IEEE-754 標準に準拠していますが、以下の点で異なります:

15.7.3. 浮動小数点の丸めとオーバーフロー

オーバーフローする計算は、無限大または最も近い有限値へ丸められることがあります。 結果は、オーバーフローした中間結果値の大きさと、評価がシェーダーモジュール生成パイプライン生成、またはシェーダー実行中かによって異なります。

浮動小数点型 T に対し、MAX(T)T の最大正有限値、 2EMAX(T)T で表現可能な最大の 2 のべき乗値と定義します。 特に EMAX(f32) = 127, EMAX(f16) = 15 です。

X を浮動小数点計算から得られる無限精度の中間結果とします。 式の最終値は、中間結果X' および X'' を介して、次のように2段階で決定されます:

X から T で丸めて X' を計算します:

X' から式の最終値 X'' を計算するか、プログラムエラーを検出します:

15.7.4. 浮動小数点精度

x を演算の無限精度で計算された実数値または無限大の正確な結果とします。 浮動小数点型 T に対する演算の 正しく丸められた結果は以下の通りです:

つまり、結果は丸めによって切り上げまたは切り下げされます: WGSL では丸めモードは指定されません。

注: 浮動小数点型には正および負の無限大が含まれるため、 正しく丸められた結果は有限値または無限大になる場合があります。

注: 無限精度で計算された演算結果は、ダブルの精度を超える精度が必要となる場合があります。 その一例として x - yx=1.0 y=1.17e-38(最小の正の正規化単精度浮動小数点数)の場合です。 これらの数値は指数が 126 離れています。IEEE-754binary64(倍精度)形式は仮数部が52ビットしかないため、 この減算では y の有効桁がすべて失われます。 丸めモードによっては、y が小さいが 0 でない場合、WGSL の式 x - yx と同じ値になることがあります。 [ECMASCRIPT] では IEEE-754 の roundTiesToEven 丸めモードに相当するものが使われています。

浮動小数点数 x の最小単位 ULP は以下のように定義されます [Muller2005]

演算の精度は次の5通りのいずれかで示されます:

演算の精度が入力範囲について指定されている場合、 その範囲外の入力値に対する精度は未定義です。

許容される結果が結果型の有限範囲外の場合、§ 15.7.3 浮動小数点の丸めとオーバーフローの規則が適用されます。

15.7.4.1. 具体的な浮動小数点式の精度
具体的な浮動小数点演算の精度
f32 の精度 f16 の精度
x + y 正しく丸め
x - y 正しく丸め
x * y 正しく丸め
x / y 2.5 ULP(|y| が [2-126, 2126] の範囲) 2.5 ULP(|y| が [2-14, 214] の範囲)
x % y x - y * trunc(x/y) から継承
-x 正しく丸め
x == y 正確な結果
x != y 正確な結果
x < y 正確な結果
x <= y 正確な結果
x > y 正確な結果
x >= y 正確な結果
具体的な浮動小数点組み込み関数の精度
組み込み関数 f32 の精度 f16 の精度
abs(x) 正しく丸め
acos(x) より悪い方:
  • 絶対誤差 6.77×10-5

  • atan2(sqrt(1.0 - x * x), x) から継承

より悪い方:
  • 絶対誤差 3.91×10-3

  • atan2(sqrt(1.0 - x * x), x) から継承

acosh(x) log(x + sqrt(x * x - 1.0)) から継承
asin(x) より悪い方:
  • 絶対誤差 6.81×10-5

  • atan2(x, sqrt(1.0 - x * x)) から継承

より悪い方:
  • 絶対誤差 3.91×10-3

  • atan2(x, sqrt(1.0 - x * 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) 正しく丸め。

無限精度の結果は min(max(x,low),high) または 3値の中央値で計算されます。 low > high の場合は異なることがあります。

x および low または high のいずれかが非正規化なら、結果は非正規化値のいずれでもよいです。 これは min および max 関数の非正規化入力に対する可能な結果に基づきます。

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])ij)から継承
degrees(x) x * 57.295779513082322865 から継承
determinant(m:mat2x2<T>)
determinant(m:mat3x3<T>)
determinant(m:mat4x4<T>)
無限 ULP。
注:WebGPU の実装は実用的な行列式関数を提供すべきです。

理想的な数学では、行列式は加算、減算、乗算で計算されます。

しかし、GPU は浮動小数点演算を用い、GPU 実装の行列式はオーバーフローや誤差への堅牢性よりも速度と単純さを重視します。

例えば、2x2 行列式の素朴な計算 (m[0][0] * m[1][1] - m[1][0] * m[0][1]) は壊滅的なキャンセルを防げません。 2x2 行列式の誤差境界を厳密化する研究は最近進んでいます [Jeannerod2013]。 行列サイズが増えると困難は急速に増します。

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 上の異なる呼び出し間の値の差(fwidth の場合は絶対値の差)として実装されます。

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) 正しく丸め

xy の両方が非正規化の場合、結果はどちらの入力でもよいです。

min(x, y) 正しく丸め

xy の両方が非正規化の場合、結果はどちらの入力でもよいです。

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) より悪い方:
  • 絶対誤差 1.0×10-5

  • sinh(x) / cosh(x) から継承

transpose(x) 正しく丸め
trunc(x) 正しく丸め
unpack4x8snorm(x) 3 ULP N/A
unpack4x8unorm(x) 3 ULP N/A
unpack2x16snorm(x) 3 ULP N/A
unpack2x16unorm(x) 3 ULP N/A
unpack2x16float(x) 正しく丸め N/A
subgroupBroadcast(x, i) 正しく丸め
subgroupBroadcastFirst(x) 正しく丸め
subgroupAdd(x) アクティブなサブグループ呼び出し全ての x の合計から継承
subgroupExclusiveAdd(x) アクティブなサブグループ呼び出しのうち、サブグループ呼び出し ID が現在の ID 未満のものの x の合計から継承
subgroupInclusiveAdd(x) アクティブなサブグループ呼び出しのうち、サブグループ呼び出し ID が現在の ID 以下のものの x の合計から継承
subgroupMul(x) アクティブなサブグループ呼び出し全ての x の積から継承
subgroupExclusiveMul(x) アクティブなサブグループ呼び出しのうち、サブグループ呼び出し ID が i 番目呼び出しの ID 未満の xi の積から継承
subgroupInclusiveMul(x) アクティブなサブグループ呼び出しのうち、サブグループ呼び出し ID が i 番目呼び出しの ID 以下の xi の積から継承
subgroupMax(x) アクティブなサブグループ呼び出し全ての max(x) から継承
subgroupMin(x) アクティブなサブグループ呼び出し全ての min(x) から継承
subgroupShuffle(x, id) 正しく丸め
subgroupShuffleDown(x, delta) 正しく丸め
subgroupShuffleUp(x, delta) 正しく丸め
subgroupShuffleXor(x, mask) 正しく丸め
quadBroadcast(x, id) 正しく丸め
quadSwapDiagonal(x) 正しく丸め
quadSwapX(x) 正しく丸め
quadSwapY(x) 正しく丸め
15.7.4.2. AbstractFloat 式の精度

AbstractFloat演算の精度は以下の通りです:

注: 絶対誤差境界を ULP で定量化する場合、基礎となる浮動小数点型に大きく依存します。

ULPAbstractFloat値の場合、 AbstractFloat が IEEE-754binary64型と同一であると仮定します。

f32値における1ULPは、IEEE-754 binary64値の1ULPの229倍の大きさです。 これは binary64 の仮数部が f32 より 29ビット長いからです。

例えば、演算の真の結果値が x だが、計算結果が x' となった場合、 その誤差 x-x' が f32 で 3ULP なら、同じ絶対誤差 x-x' は AbstractFloat では 3·229 ULP となります。

15.7.5. 再結合と融合

再結合とは、式中の演算の順序を変更し、厳密に計算した場合に同じ答えが得られるようにすることです。例:

しかし、浮動小数点で計算すると結果が異なる場合があります。 再結合された結果は近似による不正確さや、中間結果の計算でオーバーフローや NaN を引き起こす可能性があります。

実装は演算を再結合しても構いません。

実装は、変換後の式が元の形式と同等以上に精度が高ければ、演算を融合しても構いません。 例えば、融合乗算加算(fused multiply-add)実装は、乗算と加算を個別に行うより高精度な場合があります。

15.7.6. 浮動小数点変換

この節では、浮動小数点型がソースまたは変換先となるスカラー変換の詳細を説明します。

この節でいう浮動小数点型は、次のいずれかです:

注: f32 WGSL 型は IEEE-754 の binary32 形式、f16 WGSL 型は IEEE-754 の binary16 形式に対応します。

スカラー浮動小数点から整数型への変換アルゴリズム:

浮動小数点スカラー値 X整数スカラーT に変換するには:

注: NaN 以外の場合、浮動小数点から整数への変換は 変換先型の範囲内に値をクランプし、ゼロ方向に丸めます。 このクランプ要件は WGSL が意味のある結果を保証する箇所であり、C や C++ では未定義動作となり、 IEEE-754 では不正な演算例外と NaN が要求される場面です。

注: 例:

数値スカラーから浮動小数点への変換アルゴリズム:

アルゴリズム: 数値スカラー変換から浮動小数点へ

入力:

出力: XOutX を型 T に変換した結果、またはエラー

手順:

注: 整数値が2つの隣接する浮動小数点値の間に位置する場合もあります。 特に f32 型は 23ビットの仮数部を持ちます。 さらに、浮動小数点値が正規化範囲内(指数が極端でない)なら、仮数部は 小数部ビットに加え最上位の23ビット目に1ビットが追加されます。 例えば整数 228 と 1+228 は同じ浮動小数点値にマッピングされます。 最下位1ビットの差が浮動小数点型で表現できません。 このような衝突は絶対値が 225 以上の隣接整数のペアで発生します。

注: 元の型が i32 または u32 で、変換先型が f32 の場合、元の値は必ず変換先型の範囲内です。

注: ソース型がターゲット浮動小数点型より指数部・仮数部ビットが少ない場合、元の値は必ず変換先型の範囲内です。

15.7.7. 浮動小数点式および組み込み関数の定義域

前節では、浮動小数点式が定義域外で評価された場合の期待される挙動を説明しています。

§ 8.7 算術式§ 17.5 数値組み込み関数では、浮動小数点式と組み込み関数の定義域を定義しています。 特に制限がない場合、その演算の定義域は全ての有限・無限入力を含みます。 それ以外の場合は明示的な定義域が記載されています。

多くの場合、WGSL の演算が IEEE-754 で定義されている演算に対応している場合、定義域も一致します。 例えば WGSL および IEEE-754 の acos 演算は定義域が [−1,1] です。

要素単位演算で明示的な定義域がある場合は、スカラーケースのみ記載されます。ベクトルの場合は要素単位の意味から推論されます。

WGSL の一部の演算は他の WGSL 式で実装される場合があります。 § 15.7.4 浮動小数点精度では、そのような演算の精度を継承としています。 これらの演算の定義域を列挙する際は、以下のいずれかとなります:

例:2要素ベクトル ab に対する dot(a,b) 関数の精度は、式 a[0] * b[0] + a[1] * b[1] から継承されます。 これは2回の浮動小数点乗算と1回の浮動小数点加算を利用します。

したがって、定義域は以下を除く拡

16. キーワードとトークンの概要

16.1. キーワードの概要

16.2. 予約語

予約語は、将来使用のために予約されているトークンです。 WGSLモジュールは予約語を含めてはなりません

以下は予約語です:

_reserved :

| '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. 構文トークン

構文トークンは、 特殊なコードポイントの並びであり、以下の目的で使用されます:

構文トークンは次の通りです:

17. 組み込み関数

いくつかの関数は事前宣言されており、 実装によって提供されるため、WGSLモジュールで常に利用可能です。 これらは組み込み関数と呼ばれます。

組み込み関数は、同じ名前を持つ関数群であり、 それぞれは仮引数の数、順序、型によって区別されます。 それぞれの異なる関数バリエーションはオーバーロードです。

注:ユーザー定義関数は 1つのオーバーロードしか持ちません。

オーバーロードは以下の内容で記述されます:

組み込み関数を呼び出す際、すべての引数は関数の評価が始まる前に評価されます。 § 11.2 関数呼び出しを参照してください。

17.1. コンストラクタ組み込み関数

値コンストラクタ組み込み関数は、 指定した型の値を明示的に生成します。

WGSL は、すべての 事前宣言済み 型およびすべての 構築可能な 構造体型に対して値コンストラクタを提供します。 このようなコンストラクタの組み込み関数は、型名またはその型に対する 型エイリアスと同じスペルになります。 そのような組み込み関数が使用される場合、識別子は、 型または型エイリアスの スコープ内なければならず、 また 識別子は 他の宣言に 解決されてはならない 必要があります

注: frexpmodf、およびatomicCompareExchangeWeakが返す構造体型は WGSLモジュール内で記述できません。

注: その型の値宣言は、そのWGSLテキストのその文において有効でなければなりません。

WGSLは2種類の値コンストラクタを提供します:

17.1.1. ゼロ値組み込み関数

具体的構築可能Tは 一意のゼロ値を持ち、 WGSLでは型名の後に空の括弧を付けて記述します: T ()抽象数値型もゼロ値を持ちますが、 それらにアクセスする組み込み関数はありません。

ゼロ値は以下の通りです:

注: WGSLにはatomic型実行時サイズ配列、またはその他 構築可能ではない型のゼロ値組み込み関数はありません。

オーバーロード
@const @must_use fn T() -> T
パラメータ化 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)          // 同じ値を明示的に記述。
例:ゼロ値配列
array<bool, 2>()               // 2つのboolのゼロ値配列。
array<bool, 2>(false, false)   // 同じ値を明示的に記述。
例:ゼロ値構造体
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
オーバーロード
@const @must_use fn array<T, N>(e1 : T, ..., eN : T) -> array<T, N>
パラメータ化 T具体的かつ構築可能です
説明 配列を要素から構築します。

注: array<T,N>は構築可能です。なぜなら、 要素数は コンストラクタ引数の数と等しく、よって シェーダ作成時に完全に決定されるからです。

オーバーロード
@const @must_use fn array(e1 : T, ..., eN: T) -> array<T, N>
パラメータ化 T構築可能です
説明 配列を要素から構築します。

成分型は要素の型から推論されます。 配列サイズは要素数によって決まります。

17.1.2.2. bool
オーバーロード
@const @must_use fn bool(e : T) -> bool
パラメータ化 Tスカラー型です。
説明 bool値を構築します。

もしTboolなら、これは恒等操作です。
それ以外ならこれはboolへの型変換(強制)です。 eゼロ値(または浮動小数点型なら-0.0)の場合はfalse、それ以外はtrueです。

17.1.2.3. f16
オーバーロード
@const @must_use fn f16(e : T) -> f16
パラメータ化 Tスカラー型です
説明 f16値を構築します。

もしTf16なら、これは恒等操作です。
T数値型スカラーf16以外)なら、ef16に変換されます(不正な変換も含む)。
Tboolなら、 etrueのとき1.0h、それ以外は0.0hです。

17.1.2.4. f32
オーバーロード
@const @must_use fn f32(e : T) -> f32
パラメータ化 T具体的スカラー型です
説明 f32値を構築します。

もしTf32なら、これは恒等操作です。
T数値型スカラーf32以外)なら、ef32に変換されます(不正な変換も含む)。
Tboolなら、 etrueのとき1.0f、それ以外は0.0fです。

17.1.2.5. i32
オーバーロード
@const @must_use fn i32(e : T) -> i32
パラメータ化 Tスカラー型です
説明 i32値を構築します。

もしTi32なら、これは恒等操作です。
Tu32なら、これはビットの再解釈です(つまり、結果はeと同じビットパターンを持つi32の一意な値)。
T浮動小数点型なら、ei32に変換されます(ゼロ方向への丸め)。
Tboolなら、 etrueのとき1i、それ以外は0iです。
TAbstractIntなら、ei32で表現可能なら恒等操作、そうでなければシェーダ作成エラーとなります。

17.1.2.6. mat2x2
オーバーロード
@const @must_use fn mat2x2<T>(e : mat2x2<S>) -> mat2x2<T>
@const @must_use fn mat2x2(e : mat2x2<S>) -> mat2x2<S>
パラメータ化 Tf16またはf32
SAbstractFloatf16、またはf32です
説明 2x2列主導の行列のコンストラクタです。

TSが一致しない場合は変換が行われます。

オーバーロード
@const @must_use fn mat2x2<T>(v1 : vec2<T>, v2 : vec2<T>) -> mat2x2<T>
@const @must_use fn mat2x2(v1 : vec2<T>, v2 : vec2<T>) -> mat2x2<T>
パラメータ化 TAbstractFloatf16、またはf32です
説明 列ベクトルから2x2列主導行列を構築します。
オーバーロード
@const @must_use fn mat2x2<T>(e1 : T, e2 : T, e3 : T, e4 : T) -> mat2x2<T>
@const @must_use fn mat2x2(e1 : T, e2 : T, e3 : T, e4 : T) -> mat2x2<T>
パラメータ化 TAbstractFloatf16、またはf32です
説明 要素から2x2列主導行列を構築します。

mat2x2(vec2(e1,e2), vec2(e3,e4))と同じです。

17.1.2.7. mat2x3
オーバーロード
@const @must_use fn mat2x3<T>(e : mat2x3<S>) -> mat2x3<T>
@const @must_use fn mat2x3(e : mat2x3<S>) -> mat2x3<S>
パラメータ化 Tf16 または f32
SAbstractFloatf16、または f32
説明 2x3 列主導 行列のコンストラクタ。

TS が一致しない場合は、変換が行われます。

オーバーロード
@const @must_use fn mat2x3<T>(v1 : vec3<T>, v2 : vec3<T>) -> mat2x3<T>
@const @must_use fn mat2x3(v1 : vec3<T>, v2 : vec3<T>) -> mat2x3<T>
パラメータ化 TAbstractFloatf16、または f32
説明 列ベクトルから 2x3 列主導 行列を構築します。
オーバーロード
@const @must_use fn mat2x3<T>(e1 : T, ..., e6 : T) -> mat2x3<T>
@const @must_use fn mat2x3(e1 : T, ..., e6 : T) -> mat2x3<T>
パラメータ化 TAbstractFloatf16、または f32
説明 要素から 2x3 列主導 行列を構築します。

mat2x3(vec3(e1,e2,e3), vec3(e4,e5,e6)) と同じです。

17.1.2.8. mat2x4
オーバーロード
@const @must_use fn mat2x4<T>(e : mat2x4<S>) -> mat2x4<T>
@const @must_use fn mat2x4(e : mat2x4<S>) -> mat2x4<S>
パラメータ化 Tf16 または f32
SAbstractFloatf16、または f32
説明 2x4 列主導 行列のコンストラクタ。

TS が一致しない場合は、変換が行われます。

オーバーロード
@const @must_use fn mat2x4<T>(v1 : vec4<T>, v2 : vec4<T>) -> mat2x4<T>
@const @must_use fn mat2x4(v1 : vec4<T>, v2 : vec4<T>) -> mat2x4<T>
パラメータ化 TAbstractFloatf16、または f32
説明 列ベクトルから 2x4 列主導 行列を構築します。
オーバーロード
@const @must_use fn mat2x4<T>(e1 : T, ..., e8 : T) -> mat2x4<T>
@const @must_use fn mat2x4(e1 : T, ..., e8 : T) -> mat2x4<T>
パラメータ化 TAbstractFloatf16、または f32
説明 要素から 2x4 列主導 行列を構築します。

mat2x4(vec4(e1,e2,e3,e4), vec4(e5,e6,e7,e8)) と同じです。

17.1.2.9. mat3x2
オーバーロード
@const @must_use fn mat3x2<T>(e : mat3x2<S>) -> mat3x2<T>
@const @must_use fn mat3x2(e : mat3x2<S>) -> mat3x2<S>
パラメータ化 Tf16 または f32
SAbstractFloatf16、または f32
説明 3x2 列主導 行列のコンストラクタ。

TS が一致しない場合は、変換が行われます。

オーバーロード
@const @must_use fn mat3x2<T>(v1 : vec2<T>,
                              v2 : vec2<T>,
                              v3 : vec2<T>) -> mat3x2<T>
@const @must_use fn mat3x2(v1 : vec2<T>,
                           v2 : vec2<T>,
                           v3 : vec2<T>) -> mat3x2<T>
パラメータ化 TAbstractFloatf16、または f32
説明 列ベクトルから 3x2 列主導 行列を構築します。
オーバーロード
@const @must_use fn mat3x2<T>(e1 : T, ..., e6 : T) -> mat3x2<T>
@const @must_use fn mat3x2(e1 : T, ..., e6 : T) -> mat3x2<T>
パラメータ化 TAbstractFloatf16、または f32
説明 要素から 3x2 列主導 行列を構築します。

mat3x2(vec2(e1,e2), vec2(e3,e4), vec2(e5,e6)) と同じです。

17.1.2.10. mat3x3
オーバーロード
@const @must_use fn mat3x3<T>(e : mat3x3<S>) -> mat3x3<T>
@const @must_use fn mat3x3(e : mat3x3<S>) -> mat3x3<S>
パラメータ化 Tf16またはf32
SAbstractFloatf16、またはf32
説明 3x3列主導行列のコンストラクタ。

TSが一致しない場合、変換が行われます。

オーバーロード
@const @must_use fn mat3x3<T>(v1 : vec3<T>,
                              v2 : vec3<T>,
                              v3 : vec3<T>) -> mat3x3<T>
@const @must_use fn mat3x3(v1 : vec3<T>,
                           v2 : vec3<T>,
                           v3 : vec3<T>) -> mat3x3<T>
パラメータ化 TAbstractFloatf16、またはf32
説明 列ベクトルから3x3列主導行列を構築します。
オーバーロード
@const @must_use fn mat3x3<T>(e1 : T, ..., e9 : T) -> mat3x3<T>
@const @must_use fn mat3x3(e1 : T, ..., e9 : T) -> mat3x3<T>
パラメータ化 TAbstractFloatf16、またはf32
説明 要素から3x3列主導行列を構築します。

mat3x3(vec3(e1,e2,e3), vec3(e4,e5,e6), vec3(e7,e8,e9))と同じです。

17.1.2.11. mat3x4
オーバーロード
@const @must_use fn mat3x4<T>(e : mat3x4<S>) -> mat3x4<T>
@const @must_use fn mat3x4(e : mat3x4<S>) -> mat3x4<S>
パラメータ化 Tf16またはf32
SAbstractFloatf16、またはf32
説明 3x4列主導行列のコンストラクタ。

TSが一致しない場合、変換が行われます。

オーバーロード
@const @must_use fn mat3x4<T>(v1 : vec4<T>,
                              v2 : vec4<T>,
                              v3 : vec4<T>) -> mat3x4<T>
@const @must_use fn mat3x4(v1 : vec4<T>,
                           v2 : vec4<T>,
                           v3 : vec4<T>) -> mat3x4<T>
パラメータ化 TAbstractFloatf16、またはf32
説明 列ベクトルから3x4列主導行列を構築します。
オーバーロード
@const @must_use fn mat3x4<T>(e1 : T, ..., e12 : T) -> mat3x4<T>
@const @must_use fn mat3x4(e1 : T, ..., e12 : T) -> mat3x4<T>
パラメータ化 TAbstractFloatf16、またはf32
説明 要素から3x4列主導行列を構築します。

mat3x4(vec4(e1,e2,e3,e4), vec4(e5,e6,e7,e8), vec4(e9,e10,e11,e12))と同じです。

17.1.2.12. mat4x2
オーバーロード
@const @must_use fn mat4x2<T>(e : mat4x2<S>) -> mat4x2<T>
@const @must_use fn mat4x2(e : mat4x2<S>) -> mat4x2<S>
パラメータ化 Tf16またはf32
SAbstractFloatf16、またはf32
説明 4x2列主導行列のコンストラクタ。

TSが一致しない場合、型変換が行われます。

オーバーロード
@const @must_use fn mat4x2<T>(v1 : vec2<T>,
                              v2 : vec2<T>,
                              v3 : vec2<T>,
                              v4: vec2<T>) -> mat4x2<T>
@const @must_use fn mat4x2(v1 : vec2<T>,
                           v2 : vec2<T>,
                           v3 : vec2<T>,
                           v4: vec2<T>) -> mat4x2<T>
パラメータ化 TAbstractFloatf16、またはf32
説明 列ベクトルから4x2列主導行列を構築します。
オーバーロード
@const @must_use fn mat4x2<T>(e1 : T, ..., e8 : T) -> mat4x2<T>
@const @must_use fn mat4x2(e1 : T, ..., e8 : T) -> mat4x2<T>
パラメータ化 TAbstractFloatf16、またはf32
説明 要素から4x2列主導行列を構築します。

mat4x2(vec2(e1,e2), vec2(e3,e4), vec2(e5,e6), vec2(e7,e8))と同じです。

17.1.2.13. mat4x3
オーバーロード
@const @must_use fn mat4x3<T>(e : mat4x3<S>) -> mat4x3<T>
@const @must_use fn mat4x3(e : mat4x3<S>) -> mat4x3<S>
パラメータ化 Tf16またはf32
SAbstractFloatf16、またはf32
説明 4x3列主導行列のコンストラクタ。

TSが一致しない場合、型変換が行われます。

オーバーロード
@const @must_use fn mat4x3<T>(v1 : vec3<T>,
                              v2 : vec3<T>,
                              v3 : vec3<T>,
                              v4 : vec3<T>) -> mat4x3<T>
@const @must_use fn mat4x3(v1 : vec3<T>,
                           v2 : vec3<T>,
                           v3 : vec3<T>,
                           v4 : vec3<T>) -> mat4x3<T>
パラメータ化 TAbstractFloatf16、またはf32
説明 列ベクトルから4x3列主導行列を構築します。
オーバーロード
@const @must_use fn mat4x3<T>(e1 : T, ..., e12 : T) -> mat4x3<T>
@const @must_use fn mat4x3(e1 : T, ..., e12 : T) -> mat4x3<T>
パラメータ化 TAbstractFloatf16、またはf32
説明 要素から4x3列主導行列を構築します。

mat4x3(vec3(e1,e2,e3), vec3(e4,e5,e6), vec3(e7,e8,e9), vec3(e10,e11,e12))と同じです。

17.1.2.14. mat4x4
オーバーロード
@const @must_use fn mat4x4<T>(e : mat4x4<S>) -> mat4x4<T>
@const @must_use fn mat4x4(e : mat4x4<S>) -> mat4x4<S>
パラメータ化 Tf16またはf32
SAbstractFloatf16、またはf32
説明 4x4列主導行列のコンストラクタ。

TSが一致しない場合、型変換が行われます。

オーバーロード
@const @must_use fn mat4x4<T>(v1 : vec4<T>,
                              v2 : vec4<T>,
                              v3 : vec4<T>,
                              v4 : vec4<T>) -> mat4x4<T>
@const @must_use fn mat4x4(v1 : vec4<T>,
                           v2 : vec4<T>,
                           v3 : vec4<T>,
                           v4 : vec4<T>) -> mat4x4<T>
パラメータ化 TAbstractFloatf16、またはf32
説明 列ベクトルから4x4列主導行列を構築します。
オーバーロード
@const @must_use fn mat4x4<T>(e1 : T, ..., e16 : T) -> mat4x4<T>
@const @must_use fn mat4x4(e1 : T, ..., e16 : T) -> mat4x4<T>
パラメータ化 TAbstractFloatf16、または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. 構造体
オーバーロード
@const @must_use fn S(e1 : T1, ..., eN : TN) -> S
パラメータ化 Sは、メンバーの型がT1...TNである構築可能な構造体型です。
説明 メンバーから型S構造体を構築します。
17.1.2.16. u32
オーバーロード
@const @must_use fn u32(e : T) -> u32
パラメータ化 Tスカラー型です
説明 u32値を構築します。

もしTu32なら、これは恒等操作です。
Ti32なら、これはビットの再解釈です(つまり、結果はeと同じビットパターンを持つu32の一意な値)。
T浮動小数点型なら、eu32に変換されます(ゼロ方向への丸め)。
Tboolなら、 etrueのとき1u、それ以外は0uです。
TAbstractIntなら、eu32で表現可能なら恒等操作、そうでなければシェーダ作成エラーとなります。

注: AbstractIntからのオーバーロードは、u32(4*1000*1000*1000)のような式で、i32型ではオーバーフローする値もu32値として生成できるように存在します。このオーバーロードが存在しなければ、オーバーロード解決u32(i32)を選択し、AbstractInt式は自動的にi32へ変換され、オーバーフローによるシェーダ作成エラーが発生します。

17.1.2.17. vec2
オーバーロード
@const @must_use fn vec2<T>(e : T) -> vec2<T>
@const @must_use fn vec2(e : S) -> vec2<S>
パラメータ化 T具体的スカラー
Sスカラー
説明 2成分のベクトルeを両成分として構築します。
オーバーロード
@const @must_use fn vec2<T>(e : vec2<S>) -> vec2<T>
@const @must_use fn vec2(e : vec2<S>) -> vec2<S>
パラメータ化 T具体的スカラー
Sスカラー
説明 成分ごとの2成分ベクトルe.xe.yを成分として構築します。

TSが一致しない場合は、変換が行われて成分はT(e.x)T(e.y)となります。

オーバーロード
@const @must_use fn vec2<T>(e1 : T, e2 : T) -> vec2<T>
@const @must_use fn vec2(e1 : T, e2 : T) -> vec2<T>
パラメータ化 Tスカラー
説明 成分ごとの2成分ベクトルe1e2を成分として構築します。
オーバーロード
@const @must_use fn vec2() -> vec2<T>
パラメータ化 TはAbstractInt
説明 vec2(0,0)の値を返します。
17.1.2.18. vec3
オーバーロード
@const @must_use fn vec3<T>(e : T) -> vec3<T>
@const @must_use fn vec3(e : S) -> vec3<S>
パラメータ化 T具体的スカラー
Sスカラー
説明 3成分ベクトルeをすべての成分として構築します。
オーバーロード
@const @must_use fn vec3<T>(e : vec3<S>) -> vec3<T>
@const @must_use fn vec3(e : vec3<S>) -> vec3<S>
パラメータ化 T具体的スカラー
Sスカラー
説明 成分ごとの3成分ベクトルe.xe.ye.zを成分として構築します。

TSが一致しない場合は変換され、成分はT(e.x)T(e.y)T(e.z)となります。

オーバーロード
@const @must_use fn vec3<T>(e1 : T, e2 : T, e3 : T) -> vec3<T>
@const @must_use fn vec3(e1 : T, e2 : T, e3 : T) -> vec3<T>
パラメータ化 Tスカラー
説明 成分ごとの3成分ベクトルe1e2e3を成分として構築します。
オーバーロード
@const @must_use fn vec3<T>(v1 : vec2<T>, e1 : T) -> vec3<T>
@const @must_use fn vec3(v1 : vec2<T>, e1 : T) -> vec3<T>
パラメータ化 Tスカラー
説明 成分ごとの3成分ベクトルv1.xv1.ye1を成分として構築します。
オーバーロード
@const @must_use fn vec3<T>(e1 : T, v1 : vec2<T>) -> vec3<T>
@const @must_use fn vec3(e1 : T, v1 : vec2<T>) -> vec3<T>
パラメータ化 Tスカラー
説明 成分ごとの3成分ベクトルe1v1.xv1.yを成分として構築します。
オーバーロード
@const @must_use fn vec3() -> vec3<T>
パラメータ化 TはAbstractInt
説明 vec3(0,0,0)の値を返します。
17.1.2.19. vec4
オーバーロード
@const @must_use fn vec4<T>(e : T) -> vec4<T>
@const @must_use fn vec4(e : S) -> vec4<S>
パラメータ化 T具体的スカラー
Sスカラー
説明 4成分ベクトルeをすべての成分として構築します。
オーバーロード
@const @must_use fn vec4<T>(e : vec4<S>) -> vec4<T>
@const @must_use fn vec4(e : vec4<S>) -> vec4<S>
パラメータ化 T具体的スカラー
Sスカラー
説明 成分ごとの4成分ベクトルe.xe.ye.ze.wを成分として構築します。

TSが一致しない場合は変換され、成分はT(e.x)T(e.y)T(e.z)T(e.w)となります。

オーバーロード
@const @must_use fn vec4<T>(e1 : T, e2 : T, e3 : T, e4 : T) -> vec4<T>
@const @must_use fn vec4(e1 : T, e2 : T, e3 : T, e4 : T) -> vec4<T>
パラメータ化 Tスカラー
説明 成分ごとの4成分ベクトルe1e2e3e4を成分として構築します。
オーバーロード
@const @must_use fn vec4<T>(e1 : T, v1 : vec2<T>, e2 : T) -> vec4<T>
@const @must_use fn vec4(e1 : T, v1 : vec2<T>, e2 : T) -> vec4<T>
パラメータ化 Tスカラー
説明 成分ごとの4成分ベクトルe1v1.xv1.ye2を成分として構築します。
オーバーロード
@const @must_use fn vec4<T>(e1 : T, e2 : T, v1 : vec2<T>) -> vec4<T>
@const @must_use fn vec4(e1 : T, e2 : T, v1 : vec2<T>) -> vec4<T>
パラメータ化 Tスカラー
説明 成分ごとの4成分ベクトルe1e2v1.xv1.yを成分として構築します。
オーバーロード
@const @must_use fn vec4<T>(v1 : vec2<T>, v2 : vec2<T>) -> vec4<T>
@const @must_use fn vec4(v1 : vec2<T>, v2 : vec2<T>) -> vec4<T>
パラメータ化 Tスカラー
説明 成分ごとの4成分ベクトルv1.xv1.yv2.xv2.yを成分として構築します。
オーバーロード
@const @must_use fn vec4<T>(v1 : vec2<T>, e1 : T, e2 : T) -> vec4<T>
@const @must_use fn vec4(v1 : vec2<T>, e1 : T, e2 : T) -> vec4<T>
パラメータ化 Tスカラー
説明 成分ごとの4成分ベクトルv1.xv1.ye1e2を成分として構築します。
オーバーロード
@const @must_use fn vec4<T>(v1 : vec3<T>, e1 : T) -> vec4<T>
@const @must_use fn vec4(v1 : vec3<T>, e1 : T) -> vec4<T>
パラメータ化 Tスカラー
説明 成分ごとの4成分ベクトルv1.xv1.yv1.ze1を成分として構築します。
オーバーロード
@const @must_use fn vec4() -> vec4<T>
パラメータ化 TはAbstractInt
説明 vec4(0,0,0,0)の値を返します。

17.2. ビット再解釈組み込み関数

17.2.1. bitcast

bitcast 組み込み関数は、ある型の値のビット表現を別の型の値として再解釈するために使用されます。

内部レイアウトの規則は § 14.4.4 値の内部レイアウトで説明されています。

オーバーロード
@const @must_use fn bitcast<T>(e : T) -> T
パラメータ化 T具体的数値スカラー または 具体的数値ベクター
説明 恒等変換。
要素ごとTベクターの場合。
結果は e です。
オーバーロード
@const @must_use fn bitcast<T>(e : S) -> T
パラメータ化 S は i32, u32, または f32
TS ではなく、i32, u32, または f32
説明 ビットを T として再解釈します。
結果は e のビットを T 値として再解釈したものです。
オーバーロード
@const @must_use fn bitcast<vecN<T>>(e : vecN<S>) -> vecN<T>
パラメータ化 S は i32, u32, または f32
TS ではなく、i32, u32, または f32
説明 要素ごとにビットを T として再解釈します。
結果は e のビットを vecN<T> 値として再解釈したものです。
オーバーロード
@const @must_use fn bitcast<u32>(e : AbstractInt) -> u32
@const @must_use fn bitcast<vecN<u32>>(e : vecN<AbstractInt>) -> vecN<u32>
パラメータ化
説明 eu32 として表現可能な場合は恒等操作となり、 そうでない場合は シェーダー生成エラーを生成します。 つまり、u32(e) と同じ結果を生成します。

要素ごとe がベクターの場合。

オーバーロード
@const @must_use fn bitcast<T>(e : vec2<f16>) -> T
パラメータ化 T は i32, u32, または f32
説明 要素ごとにビットを T として再解釈します。
結果は e の32ビットを内部レイアウト規則に従い T 値として再解釈したものです。
オーバーロード
@const @must_use fn bitcast<vec2<T>>(e : vec4<f16>) -> vec2<T>
パラメータ化 T は i32, u32, または f32
説明 要素ごとにビットを T として再解釈します。
結果は e の64ビットを内部レイアウト規則に従い T 値として再解釈したものです。
オーバーロード
@const @must_use fn bitcast<vec2<f16>>(e : T) -> vec2<f16>
パラメータ化 T は i32, u32, または f32
説明 要素ごとにビットを f16 として再解釈します。
結果は e の32ビットを内部レイアウト規則に従い f16 値として再解釈したものです。
オーバーロード
@const @must_use fn bitcast<vec4<f16>>(e : vec2<T>) -> vec4<f16>
パラメータ化 T は i32, u32, または f32
説明 要素ごとにビットを vec2<f16> として再解釈します。
結果は e の64ビットを内部レイアウト規則に従い f16 値として再解釈したものです。

17.3. 論理組み込み関数

17.3.1. all

オーバーロード
@const @must_use fn all(e: vecN<bool>) -> bool
説明 e の各要素が true の場合に true を返します。
オーバーロード
@const @must_use fn all(e: bool) -> bool
説明 e を返します。

17.3.2. any

オーバーロード
@const @must_use fn any(e: vecN<bool>) -> bool
説明 e のいずれかの要素が true の場合に true を返します。
オーバーロード
@const @must_use fn any(e: bool) -> bool
説明 e を返します。

17.3.3. select

オーバーロード
@const @must_use fn select(f: T,
                           t: T,
                           cond: bool) -> T
パラメータ化 Tスカラー または ベクター
説明 cond が true の場合は t、そうでない場合は f を返します。
オーバーロード
@const @must_use fn select(f: vecN<T>,
                           t: vecN<T>,
                           cond: vecN<bool>) -> vecN<T>
パラメータ化 Tスカラー
説明 要素ごとに選択します。結果の要素 iselect(f[i], t[i], cond[i]) として評価されます。

17.4. 配列組み込み関数

17.4.1. arrayLength

オーバーロード
@must_use fn arrayLength(p: ptr<storage, array<E>, AM>) -> u32
パラメータ化 E実行時サイズ配列の要素型,
アクセスモード AMread または read_write
説明 NRuntime、すなわち実行時サイズ配列内の要素数を返します。

詳細は § 13.3.4 バッファバインディングによる実行時サイズ配列要素数の決定 を参照してください。

例:実行時サイズ配列の要素数の取得
struct PointLight {
  position : vec3f,
  color : vec3f,
}

struct LightStorage {
  pointCount : u32,
  point : array<PointLight>,
}

@group(0) @binding(1) var<storage> lights : LightStorage;

fn num_point_lights() -> u32 {
  return arrayLength( &lights.point );
}

17.5. 数値組み込み関数

17.5.1. abs

オーバーロード
@const @must_use fn abs(e: T ) -> T
パラメータ化 S は AbstractInt, AbstractFloat, i32, u32, f32, または f16
T は S または vecN<S>
説明 e の絶対値。 要素ごとT がベクターの場合。

e が浮動小数点型の場合、結果は正の符号ビットを持つ e です。 e が符号なし整数スカラー型の場合、結果は e です。 e が符号付き整数スカラー型で最大負値の場合、結果は e です。

17.5.2. acos

オーバーロード
@const @must_use fn acos(e: T) -> T
パラメータ化 S は AbstractFloat, f32, または f16
T は S または vecN<S>
説明 e の逆余弦(cos-1)の主値(ラジアン)を返します。
すなわち、cos(x) = e となる 0 ≤ x ≤ π の x を近似します。

要素ごとT がベクターの場合。

スカラー定義域 区間 [−1, 1]

17.5.3. acosh

オーバーロード
@const @must_use fn acosh(x: T) -> T
パラメータ化 S は AbstractFloat, f32, または f16
T は S または vecN<S>
説明 x の逆双曲線余弦(cosh-1)を双曲線角として返します。
すなわち、cosh(a) = x となる 0 ≤ a ≤ +∞ の a を近似します。

要素ごとT がベクターの場合。

スカラー定義域 区間 [1, +∞]

17.5.4. asin

オーバーロード
@const @must_use fn asin(e: T) -> T
パラメータ化 S は AbstractFloat, f32, または f16
T は S または vecN<S>
説明 e の逆正弦(sin-1)の主値(ラジアン)を返します。
すなわち、sin(x) = e となる -π/2 ≤ x ≤ π/2 の x を近似します。

要素ごとT がベクターの場合。

スカラー定義域 区間 [−1, 1]

17.5.5. asinh

オーバーロード
@const @must_use fn asinh(y: T) -> T
パラメータ化 S は AbstractFloat, f32, または f16
T は S または vecN<S>
説明 y の逆双曲線正弦(sinh-1)を双曲線角として返します。
すなわち、sinh(y) = a となる a を近似します。

要素ごとT がベクターの場合。

17.5.6. atan

オーバーロード
@const @must_use fn atan(e: T) -> T
パラメータ化 S は AbstractFloat, f32, または f16
T は S または vecN<S>
説明 e の逆正接(tan-1)の主値(ラジアン)を返します。
すなわち、tan(x) = e となる − π/2 ≤ x ≤ π/2 の x を近似します。

要素ごとT がベクターの場合。

17.5.7. atanh

オーバーロード
@const @must_use fn atanh(t: T) -> T
パラメータ化 S は AbstractFloat, f32, または f16
T は S または vecN<S>
説明 t の逆双曲線正接(tanh-1)を双曲線角として返します。
すなわち、tanh(a) = t となる a を近似します。

要素ごとT がベクターの場合。

スカラー定義域 区間 [−1, 1]

17.5.8. atan2

オーバーロード
@const @must_use fn atan2(y: T,
                          x: T) -> T
パラメータ化 S は AbstractFloat, f32, または f16
T は S または vecN<S>
説明 角度(ラジアン単位)を区間 [-π, π] で返し、その正接が y÷x となります。

結果の象限は y および x の符号に依存します。 例えば、関数は以下のように実装される場合があります:

  • x > 0 の場合 atan(y/x)

  • (x < 0) かつ (y > 0) の場合 atan(y/x) + π

  • (x < 0) かつ (y < 0) の場合 atan(y/x) - π

注: 結果の誤差は無制限です:
  • abs(x) が非常に小さい場合(例:型にとって非正規化の場合)

  • 原点 (x,y) = (0,0) の場合

  • y が非正規化または無限大の場合

要素ごとT がベクターの場合。

17.5.9. ceil

オーバーロード
@const @must_use fn ceil(e: T) -> T
パラメータ化 S は AbstractFloat, f32, または f16
T は S または vecN<S>
説明 天井(ceil)を e に対して返します。 要素ごとT がベクターの場合。

17.5.10. clamp

オーバーロード
@const @must_use fn clamp(e: T,
                          low: T,
                          high: T) -> T
パラメータ化 S は AbstractInt, AbstractFloat, i32, u32, f32, または f16
T は S または vecN<S>
説明 e の値を範囲内に制限します。

T が整数型の場合、結果は min(max(e, low), high) です。

T が浮動小数点型の場合、結果は min(max(e, low), high) または3つの値 elowhigh の中央値です。

要素ごとT がベクターの場合。

lowhigh より大きい場合:

17.5.11. cos

オーバーロード
@const @must_use fn cos(e: T) -> T
パラメータ化 S は AbstractFloat, f32, または f16
T は S または vecN<S>
説明 e(ラジアン単位)の余弦を返します。 要素ごとT がベクターの場合。
スカラー定義域 区間 (−∞, +∞)

17.5.12. cosh

オーバーロード
@const @must_use fn cosh(a: T) -> T
パラメータ化 S は AbstractFloat, f32, または f16
T は S または vecN<S>
説明 a双曲線角)の双曲線余弦を返します。 純粋な数学関数 (ea + e−a)÷2 を近似しますが、必ずしもその方法で計算されるわけではありません。

要素ごとT がベクターの場合

17.5.13. countLeadingZeros

オーバーロード
@const @must_use fn countLeadingZeros(e: T) -> T
パラメータ化 T は i32, u32, vecN<i32>, または vecN<u32>
説明 T がスカラー型の場合、e の最上位ビットから連続する 0 のビット数。
要素ごとT がベクターの場合。
一部の言語では "clz" とも呼ばれます。

17.5.14. countOneBits

オーバーロード
@const @must_use fn countOneBits(e: T) -> T
パラメータ化 T は i32, u32, vecN<i32>, または vecN<u32>
説明 e の表現に含まれる 1 のビット数。
"population count" とも呼ばれます。
要素ごとT がベクターの場合。

17.5.15. countTrailingZeros

オーバーロード
@const @must_use fn countTrailingZeros(e: T) -> T
パラメータ化 T は i32, u32, vecN<i32>, または vecN<u32>
説明 T がスカラー型の場合、e の最下位ビットから連続する 0 のビット数。
要素ごとT がベクターの場合。
一部の言語では "ctz" とも呼ばれます。

17.5.16. cross

オーバーロード
@const @must_use fn cross(a: vec3<T>,
                          b: vec3<T>) -> vec3<T>
パラメータ化 T は AbstractFloat, f32, または f16
説明 e1e2 の外積を返します。
定義域 線形項から暗黙的に決定される可能な実装:
  • a[1] × b[2] − a[2] × b[1]

  • a[2] × b[0] − a[0] × b[2]

  • a[0] × b[1] − a[1] × b[0]

17.5.17. degrees

オーバーロード
@const @must_use fn degrees(e1: T) -> T
パラメータ化 S は AbstractFloat, f32, または f16
T は S または vecN<S>
説明 ラジアンから度への変換(e1 × 180 ÷ π の近似)。 要素ごとT がベクターの場合

17.5.18. determinant

オーバーロード
@const @must_use fn determinant(e: matCxC<T>) -> T
パラメータ化 T は AbstractFloat, f32, または f16
説明 e の行列式を返します。
定義域 標準的な数学的な行列式定義における線形項から暗黙的に決定

17.5.19. distance

オーバーロード
@const @must_use fn distance(e1: T,
                             e2: T) -> S
パラメータ化 S は AbstractFloat, f32, または f16
T は S または vecN<S>
説明 e1e2 の距離を返します(例: length(e1 - e2))。

定義域は、 減算 e1e2 が有効なすべてのベクター (e1,e2) です。 すなわち、ある要素 i において e1[i]e2[i] が同じ無限値である場合を除く全てのベクター集合です。

17.5.20. dot

オーバーロード
@const @must_use fn dot(e1: vecN<T>,
                        e2: vecN<T>) -> T
パラメータ化 T は AbstractInt, AbstractFloat, i32, u32, f32, または f16
説明 e1e2 のドット積(内積)を返します。
定義域 線形項の和(e1[i] × e2[i])から暗黙的に決定されます。

17.5.21. dot4U8Packed

オーバーロード
@const @must_use fn dot4U8Packed(e1: u32,
                                 e2: u32) -> u32
説明 e1 および e2 は4つの8ビット符号なし整数成分を持つベクターとして解釈されます。 この2つのベクターの符号なし整数ドット積を返します。

17.5.22. dot4I8Packed

オーバーロード
@const @must_use fn dot4I8Packed(e1: u32,
                                 e2: u32) -> i32
説明 e1 および e2 は4つの8ビット符号付き整数成分を持つベクターとして解釈されます。 この2つのベクターの符号付き整数ドット積を返します。各成分は乗算前にi32へ符号拡張され、その後加算はWGSLのi32で行われます(加算はオーバーフローしません。結果は数学的に-65024から65536の範囲に収まるため、i32で十分表現可能です)。

17.5.23. exp

オーバーロード
@const @must_use fn exp(e1: T) -> T
パラメータ化 S は AbstractFloat, f32, または f16
T は S または vecN<S>
説明 e1 の自然指数関数(例:ee1)を返します。 要素ごとT がベクターの場合。

17.5.24. exp2

オーバーロード
@const @must_use fn exp2(e: T) -> T
パラメータ化 S は AbstractFloat, f32, または f16
T は S または vecN<S>
説明 e の2乗(例:2e)を返します。 要素ごとT がベクターの場合。

17.5.25. extractBits (signed)

オーバーロード
@const @must_use fn extractBits(e: T,
                                offset: u32,
                                count: u32) -> T
パラメータ化 T は i32 または vecN<i32>
説明 整数からビットを読み取り、符号拡張を行います。

T がスカラー型の場合:

  • wT のビット幅
  • o = min(offset, w)
  • c = min(count, w - o)
  • c が 0 の場合、結果は 0
  • それ以外の場合、結果のビット 0..c - 1e のビット o..o + c - 1 からコピーされます。 結果のその他のビットは、結果のビット c - 1 と同じです。
要素ごとT がベクターの場合。

count + offsetw より大きい場合:

17.5.26. extractBits (unsigned)

オーバーロード
@const @must_use fn extractBits(e: T,
                                offset: u32,
                                count: u32) -> T
パラメータ化 T は u32 または vecN<u32>
説明 整数からビットを読み取り、符号拡張はしません。

T がスカラー型の場合:

  • wT のビット幅
  • o = min(offset, w)
  • c = min(count, w - o)
  • c が 0 の場合、結果は 0
  • それ以外の場合、結果のビット 0..c - 1e のビット o..o + c - 1 からコピーされます。 結果のその他のビットは0です。
要素ごとT がベクターの場合。

count + offsetw より大きい場合:

17.5.27. faceForward

オーバーロード
@const @must_use fn faceForward(e1: T,
                                e2: T,
                                e3: T) -> T
パラメータ化 T は vecN<AbstractFloat>, vecN<f32>, または vecN<f16>
説明 dot(e2, e3) が負の場合は e1 を、そうでなければ -e1 を返します。
定義域 dot(e2,e3) 演算に由来する定義域制約:線形項e2[i] × e3[i])の和から暗黙的に決定されます。

17.5.28. firstLeadingBit (signed)

オーバーロード
@const @must_use fn firstLeadingBit(e: T) -> T
パラメータ化 T は i32 または vecN<i32>
説明 スカラー T の場合、結果は以下の通りです:
  • e が 0 または -1 の場合は -1
  • それ以外の場合、e の符号ビットと異なる最上位ビットの位置

要素ごとT がベクターの場合。

注:符号付き整数は2の補数表現であるため、 符号ビットは最上位ビット位置に現れます。

17.5.29. firstLeadingBit (unsigned)

オーバーロード
@const @must_use fn firstLeadingBit(e: T) -> T
パラメータ化 T は u32 または vecN<u32>
説明 スカラー T の場合、結果は以下の通りです:
  • e が0の場合は T(-1)
  • それ以外の場合、e の最上位1ビットの位置
要素ごとT がベクターの場合。

17.5.30. firstTrailingBit

オーバーロード
@const @must_use fn firstTrailingBit(e: T) -> T
パラメータ化 T は i32, u32, vecN<i32>, または vecN<u32>
説明 スカラー T の場合、結果は以下の通りです:
  • e が0の場合は T(-1)
  • それ以外の場合、e の最下位1ビットの位置
要素ごとT がベクターの場合。

17.5.31. floor

オーバーロード
@const @must_use fn floor(e: T) -> T
パラメータ化 S は AbstractFloat, f32, または f16
T は S または vecN<S>
説明 e(floor)を返します。 要素ごとT がベクターの場合。

17.5.32. fma

オーバーロード
@const @must_use fn fma(e1: T,
                        e2: T,
                        e3: T) -> T
パラメータ化 S は AbstractFloat, f32, または f16
T は S または vecN<S>
説明 e1 * e2 + e3 を返します。 要素ごとT がベクターの場合。

注: fma という名称は「fused multiply add(積和)」の略です。

注: IEEE-754fusedMultiplyAdd 演算は、中間結果を無限の範囲と精度で計算したかのように扱い、最終的な結果のみが丸められて出力型に収まります。 しかし、§ 15.7.4 浮動小数点精度fma規則では、 通常の乗算+加算で実装しても構いません。 この場合、中間結果はオーバーフローしたり精度を失ったりする可能性があり、演算は「fused」ではありません。

定義域 線形項e2 × e2 + e3)から暗黙的に決定されます。

17.5.33. fract

オーバーロード
@const @must_use fn fract(e: T) -> T
パラメータ化 S は AbstractFloat, f32, または f16
T は S または vecN<S>
説明 e - floor(e) として計算される e の小数部分を返します。
要素ごとT がベクターの場合。

注: 有効な結果は閉区間 [0, 1.0] に収まります。 例えば e が非常に小さい負値なら fract(e) は 1.0 になることがあります。

17.5.34. frexp

オーバーロード
@const @must_use fn frexp(e: T) -> __frexp_result_f32
パラメータ化 T は f32
説明 e を小数部と指数部に分割します。
  • e が 0 の場合、小数部は 0。

  • e が 0 以外かつ正規化済みの場合、e = fraction * 2exponent であり、 fraction は [0.5, 1.0) または (-1.0, -0.5] の範囲です。

  • それ以外は e非正規化、NaN、または無限大。結果の fraction と exponent は不定値です。

__frexp_result_f32 組み込み構造体を返します。定義例:

struct __frexp_result_f32 {
  fract : f32, // 小数部
  exp : i32    // 指数部
}

注: frexp という名前は「fraction(小数部)と exponent(指数部)」の略語です。

例:frexp の使用
// 型推論で結果型を決定
let fraction_and_exponent = frexp(1.5);
// fraction_only は 0.75 になる
let fraction_only = frexp(1.5).fract;

注: __frexp_result_f32 型で明示的に値を宣言することはできませんが、型推論によって決定される場合があります。

オーバーロード
@const @must_use fn frexp(e: T) -> __frexp_result_f16
パラメータ化 T は f16
説明 e を小数部と指数部に分割します。
  • e が 0 の場合、小数部は 0。

  • e が 0 以外かつ正規化済みの場合、e = fraction * 2exponent であり、 fraction は [0.5, 1.0) または (-1.0, -0.5] の範囲です。

  • それ以外は e非正規化、NaN、または無限大。結果の fraction と exponent は不定値です。

__frexp_result_f16 組み込み構造体を返します。定義例:

struct __frexp_result_f16 {
  fract : f16, // 小数部
  exp : i32    // 指数部
}

注: frexp という名前は「fraction(小数部)と exponent(指数部)」の略語です。

注: __frexp_result_f16 型で明示的に値を宣言することはできませんが、型推論によって決定される場合があります。

オーバーロード
@const @must_use fn frexp(e: T) -> __frexp_result_abstract
パラメータ化 T は AbstractFloat
説明 e を小数部と指数部に分割します。
  • e が 0 の場合、小数部は 0。

  • e が 0 以外かつ正規化済みの場合、e = fraction * 2exponent であり、 fraction は [0.5, 1.0) または (-1.0, -0.5] の範囲です。

  • e非正規化 の場合は fraction と exponent に誤差が無制限に生じます。 fraction は任意の AbstractFloat、exponent は任意の AbstractInt になります。

注: AbstractFloat 式で無限大や NaN になるとシェーダー生成エラーとなります。

__frexp_result_abstract 組み込み構造体を返します。定義例:

struct __frexp_result_abstract {
  fract : AbstractFloat, // 小数部
  exp : AbstractInt      // 指数部
}

注: frexp という名前は「fraction(小数部)と exponent(指数部)」の略語です。

例:abstract frexp の使用
// 型推論で結果型を決定
const fraction_and_exponent = frexp(1.5);
// fraction_only は 0.75 になる
const fraction_only = frexp(1.5).fract;

注: __frexp_result_abstract 型で明示的に値を宣言することはできませんが、型推論によって決定される場合があります。

オーバーロード
@const @must_use fn frexp(e: T) -> __frexp_result_vecN_f32
パラメータ化 T は vecN<f32>
説明 e の各要素 ei を小数部と指数部に分割します。
  • ei が 0 の場合、小数部は 0。

  • ei が 0 以外かつ正規化済みの場合、ei = fraction * 2exponent であり、 fraction は [0.5, 1.0) または (-1.0, -0.5] の範囲です。

  • それ以外は ei が NaN または無限大。結果の fraction と exponent は不定値です。

__frexp_result_vecN_f32 組み込み構造体を返します。定義例:

struct __frexp_result_vecN_f32 {
  fract : vecN<f32>, // 小数部
  exp : vecN<i32>    // 指数部
}

注: frexp という名前は「fraction(小数部)と exponent(指数部)」の略語です。

注: __frexp_result_vecN_f32 型で明示的に値を宣言することはできませんが、型推論によって決定される場合があります。

オーバーロード
@const @must_use fn frexp(e: T) -> __frexp_result_vecN_f16
パラメータ化 T は vecN<f16>
説明 e の各要素 ei を小数部と指数部に分割します。
  • ei が 0 の場合、小数部は 0。

  • ei が 0 以外かつ正規化済みの場合、ei = fraction * 2exponent であり、 fraction は [0.5, 1.0) または (-1.0, -0.5] の範囲です。

  • それ以外は ei が NaN または無限大。結果の fraction と exponent は不定値です。

__frexp_result_vecN_f16 組み込み構造体を返します。定義例:

struct __frexp_result_vecN_f16 {
  fract : vecN<f16>, // 小数部
  exp : vecN<i32>    // 指数部
}

注: frexp という名前は「fraction(小数部)と exponent(指数部)」の略語です。

注: __frexp_result_vecN_f16 型で明示的に値を宣言することはできませんが、型推論によって決定される場合があります。

オーバーロード
@const @must_use fn frexp(e: T) -> __frexp_result_vecN_abstract
パラメータ化 T は vecN<AbstractFloat>
説明 e の各要素 ei を小数部と指数部に分割します。
  • ei が 0 の場合、小数部は 0。

  • ei が 0 以外かつ正規化済みの場合、ei = fraction * 2exponent であり、 fraction は [0.5, 1.0) または (-1.0, -0.5] の範囲です。

  • ei非正規化 の場合は fraction と exponent に誤差が無制限に生じます。 fraction は任意の AbstractFloat、exponent は任意の AbstractInt になります。

注: AbstractFloat 式で無限大や NaN になるとシェーダー生成エラーとなります。

__frexp_result_vecN_abstract 組み込み構造体を返します。定義例:

struct __frexp_result_vecN_abstract {
  fract : vecN<AbstractFloat>, // 小数部
  exp : vecN<AbstractInt>      // 指数部
}

注: frexp という名前は「fraction(小数部)と exponent(指数部)」の略語です。

注: __frexp_result_vecN_abstract 型で明示的に値を宣言することはできませんが、型推論によって決定される場合があります。

17.5.35. insertBits

オーバーロード
@const @must_use fn insertBits(e: T,
                              newbits: T,
                              offset: u32,
                              count: u32) -> T
パラメータ化 T は i32, u32, vecN<i32>, または vecN<u32>
説明 整数のビットを設定します。

T がスカラー型の場合:

  • wT のビット幅
  • o = min(offset, w)
  • c = min(count, w - o)
  • c が 0 の場合、結果は e
  • それ以外の場合、 結果のビット o..o + c - 1newbits のビット 0..c - 1 からコピーされます。 その他のビットは e からコピーされます。
要素ごとT がベクターの場合。

count + offsetw より大きい場合:

17.5.36. inverseSqrt

オーバーロード
@const @must_use fn inverseSqrt(e: T) -> T
パラメータ化 S は AbstractFloat, f32, または f16
T は S または vecN<S>
説明 sqrt(e) の逆数を返します。 要素ごとT がベクターの場合。
スカラー定義域 区間 [0, +∞]

17.5.37. ldexp

オーバーロード
@const @must_use fn ldexp(e1: T,
                          e2: I) -> T
パラメータ化 S は AbstractFloat, f32, または f16
T は S または vecN<S>
I は AbstractInt, i32, vecN<AbstractInt>, または vecN<i32>
I がベクター型の場合に限り T もベクター型
T抽象型の場合、I抽象型でなければならず、その逆も同様

注: いずれかのパラメータが具体型の場合、 もう一方のパラメータは自動変換によって 具体型(該当する場合)となり、結果も 具体型となります。

説明 e1 * 2e2 を返します。ただし:

ここで bias は浮動小数点フォーマットの指数バイアス:

  • f16 の場合は 15

  • f32 の場合は 127

  • AbstractFloat が IEEE-754 binary64 の場合は 1023

x が0、または型に対して有限な正規値の場合:

x = ldexp(frexp(x).fract, frexp(x).exp)

要素ごとT がベクターの場合。

注: ldexp という名前は "load exponent" の略です。 PDP-11 の浮動小数点ユニットの命令から取られた可能性があります。

17.5.38. length

オーバーロード
@const @must_use fn length(e: T) -> S
パラメータ化 S は AbstractFloat, f32, または f16
T は S または vecN<S>
説明 e の長さを返します。
Tスカラーの場合は絶対値。
T がベクター型の場合は sqrt(e[0]2 + e[1]2 + ...) で評価。

注: スカラーの場合 sqrt(e * e) で評価されることがあり、 オーバーフローや精度損失が発生する場合があります。

17.5.39. log

オーバーロード
@const @must_use fn log(e: T) -> T
パラメータ化 S は AbstractFloat, f32, または f16
T は S または vecN<S>
説明 e の自然対数を返します。 要素ごとT がベクターの場合。
スカラー定義域 区間 [0, +∞]

17.5.40. log2

オーバーロード
@const @must_use fn log2(e: T) -> T
パラメータ化 S は AbstractFloat, f32, または f16
T は S または vecN<S>
説明 e の底2の対数を返します。 要素ごとT がベクターの場合。
スカラー定義域 区間 [0, +∞]

17.5.41. max

オーバーロード
@const @must_use fn max(e1: T,
                        e2: T) -> T
パラメータ化 S は AbstractInt, AbstractFloat, i32, u32, f32, または f16
T は S または vecN<S>
説明 e1e2 より小さい場合は e2 を、そうでなければ e1 を返します。 要素ごとT がベクターの場合。

e1e2 が浮動小数点値の場合:

  • e1e2 の両方が非正規化の場合、結果はどちらの値でも構いません。

17.5.42. min

オーバーロード
@const @must_use fn min(e1: T,
                        e2: T) -> T
パラメータ化 S は AbstractInt, AbstractFloat, i32, u32, f32, または f16
T は S または vecN<S>
説明 e2e1 より小さい場合は e2 を、そうでなければ e1 を返します。 要素ごとT がベクターの場合。

e1e2 が浮動小数点値の場合:

  • e1e2 の両方が非正規化の場合、結果はどちらの値でも構いません。

17.5.43. mix

オーバーロード
@const @must_use fn mix(e1: T,
                        e2: T,
                        e3: T) -> T
パラメータ化 S は AbstractFloat, f32, または f16
T は S または vecN<S>
説明 e1e2 の線形合成(例:e1 * (T(1) - e3) + e2 * e3)を返します。 要素ごとT がベクターの場合。
定義域 線形項e1[i] × (1 − e3[i]) + e2[i] × e3[i]、 e2[i] × e2[i] + e3[i])から暗黙的に決定されます。
オーバーロード
@const @must_use fn mix(e1: T2,
                        e2: T2,
                        e3: T) -> T2
パラメータ化 T は AbstractFloat, f32, または f16
T2 は vecN<T>
説明 e1e2 の要素ごとの線形合成を、スカラー合成係数 e3 で各要素に適用します。
mix(e1, e2, T2(e3)) と同じです。
定義域 線形項e1[i] × (1 − e3) + e2[i] × e3)から暗黙的に決定されます。

17.5.44. modf

オーバーロード
@const @must_use fn modf(e: T) -> __modf_result_f32
パラメータ化 T は f32
説明 e を小数部と整数部に分割します。

整数部は trunc(e)、小数部は e - trunc(e) です。

__modf_result_f32 組み込み構造体を返します。定義例:

struct __modf_result_f32 {
  fract : f32, // 小数部
  whole : f32  // 整数部
}
例:modf の使用
// 型推論で結果型を決定
let fract_and_whole = modf(1.5);
// fract_only は 0.5 になる
let fract_only = modf(1.5).fract;
// whole_only は 1.0 になる
let whole_only = modf(1.5).whole;

注: __modf_result_f32 型で明示的に値を宣言することはできませんが、型推論によって決定される場合があります。

オーバーロード
@const @must_use fn modf(e: T) -> __modf_result_f16
パラメータ化 T は f16
説明 e を小数部と整数部に分割します。

整数部は trunc(e)、小数部は e - trunc(e) です。

__modf_result_f16 組み込み構造体を返します。定義例:

struct __modf_result_f16 {
  fract : f16, // 小数部
  whole : f16  // 整数部
}

注: __modf_result_f16 型で明示的に値を宣言することはできませんが、型推論によって決定される場合があります。

オーバーロード
@const @must_use fn modf(e: T) -> __modf_result_abstract
パラメータ化 T は AbstractFloat
説明 e を小数部と整数部に分割します。

整数部は trunc(e)、小数部は e - trunc(e) です。

__modf_result_abstract 組み込み構造体を返します。定義例:

struct __modf_result_abstract {
  fract : AbstractFloat, // 小数部
  whole : AbstractFloat  // 整数部
}
例:modf abstract の使用
// 型推論で結果型を決定
const fract_and_whole = modf(1.5);
// fract_only は 0.5 になる
const fract_only = modf(1.5).fract;
// whole_only は 1.0 になる
const whole_only = modf(1.5).whole;

注: __modf_result_abstract 型で明示的に値を宣言することはできませんが、型推論によって決定される場合があります。

オーバーロード
@const @must_use fn modf(e: T) -> __modf_result_vecN_f32
パラメータ化 T は vecN<f32>
説明 e の各要素を小数部と整数部に分割します。

整数部および小数部の i 番目の要素は modf(e[i]) の整数部・小数部と同じです。

__modf_result_vecN_f32 組み込み構造体を返します。定義例:

struct __modf_result_vecN_f32 {
  fract : vecN<f32>, // 小数部
  whole : vecN<f32>  // 整数部
}

注: __modf_result_vecN_f32 型で明示的に値を宣言することはできませんが、型推論によって決定される場合があります。

オーバーロード
@const @must_use fn modf(e: T) -> __modf_result_vecN_f16
パラメータ化 T は vecN<f16>
説明 e の各要素を小数部と整数部に分割します。

整数部および小数部の i 番目の要素は modf(e[i]) の整数部・小数部と同じです。

__modf_result_vecN_f16 組み込み構造体を返します。定義例:

struct __modf_result_vecN_f16 {
  fract : vecN<f16>, // 小数部
  whole : vecN<f16>  // 整数部
}

注: __modf_result_vecN_f16 型で明示的に値を宣言することはできませんが、型推論によって決定される場合があります。

オーバーロード
@const @must_use fn modf(e: T) -> __modf_result_vecN_abstract
パラメータ化 T は vecN<AbstractFloat>
説明 e の各要素を小数部と整数部に分割します。

整数部および小数部の i 番目の要素は modf(e[i]) の整数部・小数部と同じです。

__modf_result_vecN_abstract 組み込み構造体を返します。定義例:

struct __modf_result_vecN_abstract {
  fract : vecN<AbstractFloat>, // 小数部
  whole : vecN<AbstractFloat>  // 整数部
}

注: __modf_result_vecN_abstract 型で明示的に値を宣言することはできませんが、型推論によって決定される場合があります。

17.5.45. normalize

オーバーロード
@const @must_use fn normalize(e: vecN<T> ) -> vecN<T>
パラメータ化 T は AbstractFloat, f32, または f16
説明 e と同じ方向の単位ベクトルを返します。

定義域はゼロベクトル以外のすべてのベクトルです。

17.5.46. pow

オーバーロード
@const @must_use fn pow(e1: T,
                        e2: T) -> T
パラメータ化 S は AbstractFloat, f32, または f16
T は S または vecN<S>
説明 e1e2 乗を返します。 要素ごとT がベクターの場合。
スカラー定義域 拡張実数 (x,y) の全ての組み合わせ。ただし:
  • x < 0。

  • x が 1 かつ y が無限大。

  • x が無限大かつ y が 0。

結果が exp2(y * log2(x)) で計算される場合があるため、この規則が適用されます。

17.5.47. quantizeToF16

オーバーロード
@const @must_use fn quantizeToF16(e: T) -> T
パラメータ化 T は f32 または vecN<f32>
説明 32ビット浮動小数点値 e を、 IEEE-754binary16 値に変換し、さらに IEEE-754 binary32 値に戻したかのように量子化します。

e が binary16 の有限範囲外の場合:

中間の binary16 値はゼロクリアされる場合があります。すなわち、 中間の binary16 値が非正規化の場合、最終結果がゼロになる場合があります。

§ 15.7.6 浮動小数点変換も参照。

要素ごとT がベクターの場合。

注: vec2<f32> の場合は unpack2x16float(pack2x16float(e)) と同じです。

17.5.48. radians

オーバーロード
@const @must_use fn radians(e1: T) -> T
パラメータ化 S は AbstractFloat, f32, または f16
T は S または vecN<S>
説明 度からラジアンへの変換(e1 × π ÷ 180 の近似)。 要素ごとT がベクターの場合

17.5.49. reflect

オーバーロード
@const @must_use fn reflect(e1: T,
                            e2: T) -> T
パラメータ化 T は vecN<AbstractFloat>, vecN<f32>, または vecN<f16>
説明 入射ベクトル e1 と表面の向き e2 について、 反射方向 e1 - 2 * dot(e2, e1) * e2 を返します。

17.5.50. refract

オーバーロード
@const @must_use fn refract(e1: T,
                            e2: T,
                            e3: I) -> T
パラメータ化 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

オーバーロード
@const @must_use fn reverseBits(e: T) -> T
パラメータ化 T は i32, u32, vecN<i32>, または vecN<u32>
説明 e のビットを反転します:結果のビット位置 ke のビット位置 31 -k と等しくなります。
要素ごとT がベクターの場合。

17.5.52. round

オーバーロード
@const @must_use fn round(e: T) -> T
パラメータ化 S は AbstractFloat, f32, または f16
T は S または vecN<S>
説明 結果は e に最も近い整数 k(浮動小数点値)になります。
e が整数 kk + 1 のちょうど中間の場合は、 k が偶数なら k を、奇数なら k + 1 を返します。
要素ごとT がベクターの場合。

17.5.53. saturate

オーバーロード
@const @must_use fn saturate(e: T) -> T
パラメータ化 S は AbstractFloat, f32, または f16
T は S または vecN<S>
説明 clamp(e, 0.0, 1.0) を返します。 要素ごとT がベクターの場合。

17.5.54. sign

オーバーロード
@const @must_use fn sign(e: T) -> T
パラメータ化 S は AbstractInt, AbstractFloat, i32, f32, または f16
T は S または vecN<S>
説明 結果は以下の通りです:
  • e > 0 の場合は 1
  • e = 0 の場合は 0
  • e < 0 の場合は -1

要素ごとT がベクターの場合。

17.5.55. sin

オーバーロード
@const @must_use fn sin(e: T) -> T
パラメータ化 S は AbstractFloat, f32, または f16
T は S または vecN<S>
説明 e(ラジアン単位)の正弦を返します。 要素ごとT がベクターの場合。
スカラー定義域 区間 (−∞, +∞)

17.5.56. sinh

オーバーロード
@const @must_use fn sinh(a: T) -> T
パラメータ化 S は AbstractFloat, f32, または f16
T は S または vecN<S>
説明 a双曲線角)の双曲線正弦を返します。 純粋な数学関数 (eae−a)÷2 を近似しますが、必ずしもその方法で計算されるわけではありません。

要素ごとT がベクターの場合。

17.5.57. smoothstep

オーバーロード
@const @must_use fn smoothstep(edge0: T,
                               edge1: T,
                               x: T) -> T
パラメータ化 S は AbstractFloat, f32, または f16
T は S または vecN<S>
説明 0 から 1 へのスムーズなエルミート補間を返します。 要素ごとT がベクターの場合。

スカラー T の場合、結果は t * t * (3.0 - 2.0 * t) です。
ここで t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0) です。

定性的には:

  • edge0 < edge1 の場合、関数は xedge0 未満では 0、xedge1 に達するまでスムーズに上昇し、その後は 1。

  • edge0 > edge1 の場合、関数は xedge1 未満では 1、xedge0 に達するまでスムーズに下降し、その後は 0。

edge0 = edge1 の場合:

17.5.58. sqrt

オーバーロード
@const @must_use fn sqrt(e: T) -> T
パラメータ化 S は AbstractFloat, f32, または f16
T は S または vecN<S>
説明 e の平方根を返します。 要素ごとT がベクターの場合。
スカラー定義域 区間 [0, +∞]

17.5.59. step

オーバーロード
@const @must_use fn step(edge: T,
                         x: T) -> T
パラメータ化 S は AbstractFloat, f32, または f16
T は S または vecN<S>
説明 edgex の場合は 1.0、そうでなければ 0.0 を返します。 要素ごとT がベクターの場合。

17.5.60. tan

オーバーロード
@const @must_use fn tan(e: T) -> T
パラメータ化 S は AbstractFloat, f32, または f16
T は S または vecN<S>
説明 e(ラジアン単位)の正接を返します。 要素ごとT がベクターの場合。
スカラー定義域 区間 (−∞, +∞)

17.5.61. tanh

オーバーロード
@const @must_use fn tanh(a: T) -> T
パラメータ化 S は AbstractFloat, f32, または f16
T は S または vecN<S>
説明 a双曲線角)の双曲線正接を返します。 純粋な数学関数 (eae−a) ÷ (ea + e−a) を近似しますが、必ずしもその方法で計算されるわけではありません。

要素ごとT がベクターの場合。

17.5.62. transpose

オーバーロード
@const @must_use fn transpose(e: matRxC<T>) -> matCxR<T>
パラメータ化 T は AbstractFloat, f32, または f16
説明 e の転置行列を返します。

17.5.63. trunc

オーバーロード
@const @must_use fn trunc(e: T) -> T
パラメータ化 S は AbstractFloat, f32, または f16
T は S または vecN<S>
説明 truncate(e)、すなわち絶対値が e の絶対値以下となる最も近い整数値を返します。 要素ごとT がベクターの場合。

17.6. 微分組み込み関数

§ 15.6.2 微分 を参照。

これらの関数の呼び出し:

17.6.1. dpdx

オーバーロード
@must_use fn dpdx(e: T) -> T
パラメータ化 T は f32 または vecN<f32>
説明 ウィンドウ座標 x に関する e の偏微分。 結果は dpdxFine(e) または dpdxCoarse(e) のいずれかと同じです。

非一様な制御フローで呼び出した場合、不定値を返します。

17.6.2. dpdxCoarse

オーバーロード
@must_use fn dpdxCoarse(e: T) -> T
パラメータ化 T は f32 または vecN<f32>
説明 ウィンドウ座標 x に関する e の偏微分(局所差分を利用)。 dpdxFine(e) よりも一意の位置が少なくなる場合があります。

非一様な制御フローで呼び出した場合、不定値を返します。

17.6.3. dpdxFine

オーバーロード
@must_use fn dpdxFine(e: T) -> T
パラメータ化 T は f32 または vecN<f32>
説明 ウィンドウ座標 x に関する e の偏微分を返します。

非一様な制御フローで呼び出した場合、不定値を返します。

17.6.4. dpdy

オーバーロード
@must_use fn dpdy(e: T) -> T
パラメータ化 T は f32 または vecN<f32>
説明 ウィンドウ座標 y に関する e の偏微分。 結果は dpdyFine(e) または dpdyCoarse(e) のいずれかと同じです。

非一様な制御フローで呼び出した場合、不定値を返します。

17.6.5. dpdyCoarse

オーバーロード
@must_use fn dpdyCoarse(e: T) -> T
パラメータ化 T は f32 または vecN<f32>
説明 ウィンドウ座標 y に関する e の偏微分(局所差分を利用)。 dpdyFine(e) よりも一意の位置が少なくなる場合があります。

非一様な制御フローで呼び出した場合、不定値を返します。

17.6.6. dpdyFine

オーバーロード
@must_use fn dpdyFine(e: T) -> T
パラメータ化 T は f32 または vecN<f32>
説明 ウィンドウ座標 y に関する e の偏微分を返します。

非一様な制御フローで呼び出した場合、不定値を返します。

17.6.7. fwidth

オーバーロード
@must_use fn fwidth(e: T) -> T
パラメータ化 T は f32 または vecN<f32>
説明 abs(dpdx(e)) + abs(dpdy(e)) を返します。

非一様な制御フローで呼び出した場合、不定値を返します。

17.6.8. fwidthCoarse

オーバーロード
@must_use fn fwidthCoarse(e: T) -> T
パラメータ化 T は f32 または vecN<f32>
説明 abs(dpdxCoarse(e)) + abs(dpdyCoarse(e)) を返します。

非一様な制御フローで呼び出した場合、不定値を返します。

17.6.9. fwidthFine

オーバーロード
@must_use fn fwidthFine(e: T) -> T
パラメータ化 T は f32 または vecN<f32>
説明 abs(dpdxFine(e)) + abs(dpdyFine(e)) を返します。

非一様な制御フローで呼び出した場合、不定値を返します。

17.7. テクスチャ組み込み関数

パラメータ値は、各テクスチャ型に対して有効である必要があります(必須)。

17.7.1. textureDimensions

テクスチャまたはテクスチャのミップレベルの次元(テクセル数)を返します。

パラメータ化 オーバーロード
STi32, u32, または f32
Fテクセルフォーマット
Aアクセスモード

Ttexture_1d<ST> または texture_storage_1d<F,A>
@must_use fn textureDimensions(t: T) -> u32
STi32, u32, または f32

Ttexture_1d<ST>

Li32 または u32

@must_use fn textureDimensions(t: T,
                               level: L) -> u32
STi32, u32, または f32
Fテクセルフォーマット
Aアクセスモード

Ttexture_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
@must_use fn textureDimensions(t: T) -> vec2<u32>
STi32, u32, または f32

Ttexture_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

Li32 または u32

@must_use fn textureDimensions(t: T,
                               level: L) -> vec2<u32>
STi32, u32, または f32
Fテクセルフォーマット
Aアクセスモード

Ttexture_3d<ST> または texture_storage_3d<F,A>
@must_use fn textureDimensions(t: T) -> vec3<u32>
STi32, u32, または f32

Ttexture_3d<ST>

Li32 または u32

@must_use fn textureDimensions(t: T,
                               level: L) -> vec3<u32>

パラメータ:

t サンプルテクスチャ型マルチサンプルテクスチャ型デプステクスチャ型ストレージテクスチャ型、または 外部テクスチャ型 のいずれかのテクスチャ。
level ミップレベル。レベル0がテクスチャのフルサイズです。
省略時はレベル0の次元を返します。

戻り値:

テクスチャの座標次元を返します。

つまり、戻り値は論理テクセルアドレスの座標の整数範囲を示し、 ミップレベル数配列サイズサンプル数は含みません。

キューブ型テクスチャの場合、各面の次元を返します。 キューブ面は正方形なので、戻り値の x, y 成分は等しくなります。

level が範囲 [0, textureNumLevels(t)) の外の場合、戻り値型の不定値 を返す場合があります。

17.7.2. textureGather

テクスチャギャザー 操作は2D、2D配列、キューブ、またはキューブ配列テクスチャから読み込み、 以下のように4成分のベクターを計算します:

4つのテクセルは、WebGPU サンプラー記述子に記載されたサンプリング領域を形成します。

パラメータ化 オーバーロード
Ci32またはu32
STi32u32f32
@must_use fn textureGather(component: C,
                           t: texture_2d<ST>,
                           s: sampler,
                           coords: vec2<f32>) -> vec4<ST>
Ci32またはu32
STi32u32f32
@must_use fn textureGather(component: C,
                           t: texture_2d<ST>,
                           s: sampler,
                           coords: vec2<f32>,
                           offset: vec2<i32>) -> vec4<ST>
Ci32またはu32
Ai32またはu32
STi32u32f32
@must_use fn textureGather(component: C,
                           t: texture_2d_array<ST>,
                           s: sampler,
                           coords: vec2<f32>,
                           array_index: A) -> vec4<ST>
Ci32またはu32
Ai32またはu32
STi32u32f32
@must_use fn textureGather(component: C,
                           t: texture_2d_array<ST>,
                           s: sampler,
                           coords: vec2<f32>,
                           array_index: A,
                           offset: vec2<i32>) -> vec4<ST>
Ci32またはu32
STi32u32f32
@must_use fn textureGather(component: C,
                           t: texture_cube<ST>,
                           s: sampler,
                           coords: vec3<f32>) -> vec4<ST>
Ci32またはu32
Ai32またはu32
STi32u32f32
@must_use fn textureGather(component: C,
                           t: texture_cube_array<ST>,
                           s: sampler,
                           coords: vec3<f32>,
                           array_index: A) -> vec4<ST>
@must_use fn textureGather(t: texture_depth_2d,
                           s: sampler,
                           coords: vec2<f32>) -> vec4<f32>
@must_use fn textureGather(t: texture_depth_2d,
                           s: sampler,
                           coords: vec2<f32>,
                           offset: vec2<i32>) -> vec4<f32>
@must_use fn textureGather(t: texture_depth_cube,
                           s: sampler,
                           coords: vec3<f32>) -> vec4<f32>
Ai32またはu32
@must_use fn textureGather(t: texture_depth_2d_array,
                           s: sampler,
                           coords: vec2<f32>,
                           array_index: A) -> vec4<f32>
Ai32またはu32
@must_use fn textureGather(t: texture_depth_2d_array,
                           s: sampler,
                           coords: vec2<f32>,
                           array_index: A,
                           offset: vec2<i32>) -> vec4<f32>
Ai32またはu32
@must_use fn textureGather(t: texture_depth_cube_array,
                           s: sampler,
                           coords: vec3<f32>,
                           array_index: A) -> vec4<f32>

パラメータ:

component 非デプステクスチャにのみ適用されます。
選択されたテクセルから読み取るチャンネルのインデックス。
指定された場合、component式は必須定数式(例:1)でなければなりません。
値は0以上3以下である必要があります。 この範囲外の値はシェーダー生成エラーになります。
t 読み込み対象のサンプルテクスチャ型またはデプステクスチャ型
s サンプラー型
coords テクスチャ座標。
array_index 0始まりのテクスチャ配列インデックス。
この値は必ず[0, textureNumLayers(t) - 1]の範囲にクランプされます。
offset サンプリング前に非正規化テクスチャ座標に適用されるオプションのテクセルオフセット。 このオフセットは、テクスチャラッピングモード適用前に適用されます。
offset式は必須定数式(例:vec2<i32>(1, 2))でなければなりません。
offset成分は必須-8以上7以下である必要があります。この範囲外はシェーダー生成エラーです。

戻り値:

選択されたテクセルから指定チャンネルの成分を抜き出して並べた4成分ベクターを返します(上記参照)。

例:2Dテクスチャのテクセルから成分をギャザー
@group(0) @binding(0) var t: texture_2d<f32>;
@group(0) @binding(1) var dt: texture_depth_2d;
@group(0) @binding(2) var s: sampler;

fn gather_x_components(c: vec2<f32>) -> vec4<f32> {
  return textureGather(0,t,s,c);
}
fn gather_y_components(c: vec2<f32>) -> vec4<f32> {
  return textureGather(1,t,s,c);
}
fn gather_z_components(c: vec2<f32>) -> vec4<f32> {
  return textureGather(2,t,s,c);
}
fn gather_depth_components(c: vec2<f32>) -> vec4<f32> {
  return textureGather(dt,s,c);
}

17.7.3. textureGatherCompare

テクスチャギャザー比較操作は、デプステクスチャ内の4つのテクセルについて深度比較を行い、結果を1つのベクターにまとめて返します:

パラメータ化 オーバーロード
@must_use fn textureGatherCompare(t: texture_depth_2d,
                                  s: sampler_comparison,
                                  coords: vec2<f32>,
                                  depth_ref: f32) -> vec4<f32>
@must_use fn textureGatherCompare(t: texture_depth_2d,
                                  s: sampler_comparison,
                                  coords: vec2<f32>,
                                  depth_ref: f32,
                                  offset: vec2<i32>) -> vec4<f32>
Ai32またはu32
@must_use fn textureGatherCompare(t: texture_depth_2d_array,
                                  s: sampler_comparison,
                                  coords: vec2<f32>,
                                  array_index: A,
                                  depth_ref: f32) -> vec4<f32>
Ai32またはu32
@must_use fn textureGatherCompare(t: texture_depth_2d_array,
                                  s: sampler_comparison,
                                  coords: vec2<f32>,
                                  array_index: A,
                                  depth_ref: f32,
                                  offset: vec2<i32>) -> vec4<f32>
@must_use fn textureGatherCompare(t: texture_depth_cube,
                                  s: sampler_comparison,
                                  coords: vec3<f32>,
                                  depth_ref: f32) -> vec4<f32>
Ai32またはu32
@must_use fn textureGatherCompare(t: texture_depth_cube_array,
                                  s: sampler_comparison,
                                  coords: vec3<f32>,
                                  array_index: A,
                                  depth_ref: f32) -> vec4<f32>

パラメータ:

t 読み込み対象のデプステクスチャ
s 比較サンプラー
coords テクスチャ座標。
array_index 0始まりのテクスチャ配列インデックス。
この値は必ず[0, textureNumLayers(t) - 1]の範囲にクランプされます。
depth_ref サンプリングされた深度値と比較する参照値。
offset サンプリング前に非正規化テクスチャ座標に適用されるオプションのテクセルオフセット。 このオフセットは、テクスチャラッピングモード適用前に適用されます。
offset式は必須定数式(例:vec2<i32>(1, 2))でなければなりません。
offset成分は必須-8以上7以下である必要があります。この範囲外はシェーダー生成エラーです。

戻り値:

選択したテクセルの比較結果を成分とする4成分ベクター(上記参照)を返します。

例:深度比較ギャザー
@group(0) @binding(0) var dt: texture_depth_2d;
@group(0) @binding(1) var s: sampler;

fn gather_depth_compare(c: vec2<f32>, depth_ref: f32) -> vec4<f32> {
  return textureGatherCompare(dt,s,c,depth_ref);
}

17.7.4. textureLoad

サンプリングやフィルタリングを行わずに、テクスチャから単一のテクセルを読み取ります。

パラメータ化 オーバーロード
Ci32またはu32
Li32またはu32
STi32u32、またはf32
@must_use fn textureLoad(t: texture_1d<ST>,
                         coords: C,
                         level: L) -> vec4<ST>
Ci32またはu32
Li32またはu32
STi32u32、またはf32
@must_use fn textureLoad(t: texture_2d<ST>,
                         coords: vec2<C>,
                         level: L) -> vec4<ST>
Ci32またはu32
Ai32またはu32
Li32またはu32
STi32u32、またはf32
@must_use fn textureLoad(t: texture_2d_array<ST>,
                        coords: vec2<C>,
                        array_index: A,
                        level: L) -> vec4<ST>
Ci32またはu32
Li32またはu32
STi32u32、またはf32
@must_use fn textureLoad(t: texture_3d<ST>,
                         coords: vec3<C>,
                         level: L) -> vec4<ST>
Ci32またはu32
Si32またはu32
STi32u32、またはf32
@must_use fn textureLoad(t: texture_multisampled_2d<ST>,
                         coords: vec2<C>,
                         sample_index: S)-> vec4<ST>
Ci32またはu32
Li32またはu32
@must_use fn textureLoad(t: texture_depth_2d,
                         coords: vec2<C>,
                         level: L) -> f32
Ci32またはu32
Ai32またはu32
Li32またはu32
@must_use fn textureLoad(t: texture_depth_2d_array,
                         coords: vec2<C>,
                         array_index: A,
                         level: L) -> f32
Ci32またはu32
Si32またはu32
@must_use fn textureLoad(t: texture_depth_multisampled_2d,
                         coords: vec2<C>,
                         sample_index: S)-> f32
Ci32またはu32
@must_use fn textureLoad(t: texture_external,
                         coords: vec2<C>) -> vec4<f32>
Ci32またはu32
AMread またはread_write
CFはストレージテクセルフォーマットFに依存します。 テクセルフォーマット表で テクセルフォーマットとチャンネルフォーマットの対応を確認してください。
@must_use fn textureLoad(t : texture_storage_1d<F, AM>,
                         coords : C) -> vec4<CF>
Ci32またはu32
AMread またはread_write
CFはストレージテクセルフォーマットFに依存します。 テクセルフォーマット表で テクセルフォーマットとチャンネルフォーマットの対応を確認してください。
@must_use fn textureLoad(t : texture_storage_2d<F, AM>,
                         coords : vec2<C>) -> vec4<CF>
Ci32またはu32
AMread またはread_write
Ai32またはu32
CFはストレージテクセルフォーマットFに依存します。 テクセルフォーマット表で テクセルフォーマットとチャンネルフォーマットの対応を確認してください。
@must_use fn textureLoad(t : texture_storage_2d_array<F, AM>,
                         coords : vec2<C>,
                         array_index : A) -> vec4<CF>
Ci32またはu32
AMread またはread_write
CFはストレージテクセルフォーマットFに依存します。 テクセルフォーマット表で テクセルフォーマットとチャンネルフォーマットの対応を確認してください。
@must_use fn textureLoad(t : texture_storage_3d<F, AM>,
                         coords : vec3<C>) -> vec4<CF>

パラメータ:

t サンプルテクスチャマルチサンプルテクスチャデプステクスチャストレージテクスチャ、または 外部テクスチャ
coords 0始まりのテクセル座標。
array_index 0始まりのテクスチャ配列インデックス。
level ミップレベル。レベル0はテクスチャのフルサイズ。
sample_index マルチサンプルテクスチャの0始まりのサンプルインデックス。

戻り値:

フィルタリングされていないテクセルデータ。

論理テクセルアドレスが不正な場合:

論理テクセルアドレスが不正な場合、組み込み関数は次のいずれかを返します:

17.7.5. textureNumLayers

配列化テクスチャのレイヤー(要素)数を返します。

パラメータ化 オーバーロード
Fテクセルフォーマット
Aアクセスモード
STi32u32、またはf32

Ttexture_2d_array<ST>texture_cube_array<ST>texture_depth_2d_arraytexture_depth_cube_array、 またはtexture_storage_2d_array<F,A>
@must_use fn textureNumLayers(t: T) -> u32

パラメータ:

t サンプルテクスチャデプステクスチャ、 または ストレージテクスチャの配列テクスチャ。

戻り値:

テクスチャがキューブベースの場合は、キューブ配列テクスチャ内のキューブ数を返します。

それ以外の場合は、配列化テクスチャ内のレイヤー(テクセルの同種グリッド)数を返します。

17.7.6. textureNumLevels

テクスチャのミップレベル数を返します。

パラメータ化 オーバーロード
STi32u32、またはf32

Ttexture_1d<ST>texture_2d<ST>texture_2d_array<ST>texture_3d<ST>texture_cube<ST>texture_cube_array<ST>texture_depth_2dtexture_depth_2d_arraytexture_depth_cube、またはtexture_depth_cube_array
@must_use fn textureNumLevels(t: T) -> u32

パラメータ:

t サンプルテクスチャまたはデプステクスチャ

戻り値:

テクスチャのミップレベル数を返します。

17.7.7. textureNumSamples

マルチサンプルテクスチャ内のテクセルごとのサンプル数を返します。

パラメータ化 オーバーロード
STi32u32、またはf32

Ttexture_multisampled_2d<ST> またはtexture_depth_multisampled_2d
@must_use fn textureNumSamples(t: T) -> u32

パラメータ:

t マルチサンプルテクスチャ

戻り値:

サンプル数マルチサンプルテクスチャに対して返します。

17.7.8. textureSample

テクスチャをサンプリングします。

必須フラグメントシェーダーステージのみで使用してください。

この関数の呼び出しが一様な制御フローであることを一様性解析が証明できない場合、 derivative_uniformity 診断発動します。

パラメータ化 オーバーロード
@must_use fn textureSample(t: texture_1d<f32>,
                           s: sampler,
                           coords: f32) -> vec4<f32>
@must_use fn textureSample(t: texture_2d<f32>,
                           s: sampler,
                           coords: vec2<f32>) -> vec4<f32>
@must_use fn textureSample(t: texture_2d<f32>,
                           s: sampler,
                           coords: vec2<f32>,
                           offset: vec2<i32>) -> vec4<f32>
Ai32またはu32
@must_use fn textureSample(t: texture_2d_array<f32>,
                           s: sampler,
                           coords: vec2<f32>,
                           array_index: A) -> vec4<f32>
Ai32またはu32
@must_use fn textureSample(t: texture_2d_array<f32>,
                           s: sampler,
                           coords: vec2<f32>,
                           array_index: A,
                           offset: vec2<i32>) -> vec4<f32>
Ttexture_3d<f32>またはtexture_cube<f32>
@must_use fn textureSample(t: T,
                           s: sampler,
                           coords: vec3<f32>) -> vec4<f32>
@must_use fn textureSample(t: texture_3d<f32>,
                           s: sampler,
                           coords: vec3<f32>,
                           offset: vec3<i32>) -> vec4<f32>
Ai32またはu32
@must_use fn textureSample(t: texture_cube_array<f32>,
                           s: sampler,
                           coords: vec3<f32>,
                           array_index: A) -> vec4<f32>
@must_use fn textureSample(t: texture_depth_2d,
                           s: sampler,
                           coords: vec2<f32>) -> f32
@must_use fn textureSample(t: texture_depth_2d,
                           s: sampler,
                           coords: vec2<f32>,
                           offset: vec2<i32>) -> f32
Ai32またはu32
@must_use fn textureSample(t: texture_depth_2d_array,
                           s: sampler,
                           coords: vec2<f32>,
                           array_index: A) -> f32
Ai32またはu32
@must_use fn textureSample(t: texture_depth_2d_array,
                           s: sampler,
                           coords: vec2<f32>,
                           array_index: A,
                           offset: vec2<i32>) -> f32
@must_use fn textureSample(t: texture_depth_cube,
                           s: sampler,
                           coords: vec3<f32>) -> f32
Ai32またはu32
@must_use fn textureSample(t: texture_depth_cube_array,
                           s: sampler,
                           coords: vec3<f32>,
                           array_index: A) -> f32

パラメータ:

t サンプリング対象のサンプルテクスチャまたはデプステクスチャ
s サンプラー型。
coords サンプリングに使用するテクスチャ座標。
array_index サンプリング対象の0始まりのテクスチャ配列インデックス。
この値は必ず[0, textureNumLayers(t) - 1]の範囲にクランプされます。
offset サンプリング前に非正規化テクスチャ座標に適用されるオプションのテクセルオフセット。 このオフセットは、テクスチャラッピングモード適用前に適用されます。
offset式は必須定数式(例:vec2<i32>(1, 2))でなければなりません。
offset成分は必須-8以上7以下である必要があります。この範囲外はシェーダー生成エラーです。

戻り値:

サンプリングされた値。

非一様な制御フローで呼び出した場合は不定値となります。

17.7.9. textureSampleBias

ミップレベルにバイアスをかけてテクスチャをサンプリングします。

必須フラグメントシェーダーステージのみで使用してください。

この関数の呼び出しが一様な制御フローであることを一様性解析が証明できない場合、 derivative_uniformity 診断発動します。

パラメータ化 オーバーロード
@must_use fn textureSampleBias(t: texture_2d<f32>,
                               s: sampler,
                               coords: vec2<f32>,
                               bias: f32) -> vec4<f32>
@must_use fn textureSampleBias(t: texture_2d<f32>,
                               s: sampler,
                               coords: vec2<f32>,
                               bias: f32,
                               offset: vec2<i32>) -> vec4<f32>
Ai32またはu32
@must_use fn textureSampleBias(t: texture_2d_array<f32>,
                               s: sampler,
                               coords: vec2<f32>,
                               array_index: A,
                               bias: f32) -> vec4<f32>
Ai32またはu32
@must_use fn textureSampleBias(t: texture_2d_array<f32>,
                               s: sampler,
                               coords: vec2<f32>,
                               array_index: A,
                               bias: f32,
                               offset: vec2<i32>) -> vec4<f32>
Ttexture_3d<f32>またはtexture_cube<f32>
@must_use fn textureSampleBias(t: T,
                               s: sampler,
                               coords: vec3<f32>,
                               bias: f32) -> vec4<f32>
@must_use fn textureSampleBias(t: texture_3d<f32>,
                               s: sampler,
                               coords: vec3<f32>,
                               bias: f32,
                               offset: vec3<i32>) -> vec4<f32>
Ai32またはu32
@must_use fn textureSampleBias(t: texture_cube_array<f32>,
                               s: sampler,
                               coords: vec3<f32>,
                               array_index: A,
                               bias: f32) -> vec4<f32>

パラメータ:

t サンプリング対象のサンプルテクスチャ
s サンプラー型。
coords サンプリングに使用するテクスチャ座標。
array_index サンプリング対象の0始まりのテクスチャ配列インデックス。
この値は必ず[0, textureNumLayers(t) - 1]の範囲にクランプされます。
bias サンプリング前にミップレベルへ適用するバイアス。
この値は必ず[-16.0, 15.99]の範囲にクランプされます。
offset サンプリング前に非正規化テクスチャ座標に適用されるオプションのテクセルオフセット。 このオフセットは、テクスチャラッピングモード適用前に適用されます。
offset式は必須定数式(例:vec2<i32>(1, 2))でなければなりません。
offset成分は必須-8以上7以下である必要があります。この範囲外はシェーダー生成エラーです。

戻り値:

サンプリングされた値。

17.7.10. textureSampleCompare

デプステクスチャをサンプリングし、サンプリングされた深度値を参照値と比較します。

必須フラグメントシェーダーステージのみで使用してください。

この関数の呼び出しが一様な制御フローであることを一様性解析が証明できない場合、 derivative_uniformity 診断発動します。

パラメータ化 オーバーロード
@must_use fn textureSampleCompare(t: texture_depth_2d,
                                  s: sampler_comparison,
                                  coords: vec2<f32>,
                                  depth_ref: f32) -> f32
@must_use fn textureSampleCompare(t: texture_depth_2d,
                                  s: sampler_comparison,
                                  coords: vec2<f32>,
                                  depth_ref: f32,
                                  offset: vec2<i32>) -> f32
Ai32またはu32
@must_use fn textureSampleCompare(t: texture_depth_2d_array,
                                  s: sampler_comparison,
                                  coords: vec2<f32>,
                                  array_index: A,
                                  depth_ref: f32) -> f32
Ai32またはu32
@must_use fn textureSampleCompare(t: texture_depth_2d_array,
                                  s: sampler_comparison,
                                  coords: vec2<f32>,
                                  array_index: A,
                                  depth_ref: f32,
                                  offset: vec2<i32>) -> f32
@must_use fn textureSampleCompare(t: texture_depth_cube,
                                  s: sampler_comparison,
                                  coords: vec3<f32>,
                                  depth_ref: f32) -> f32
Ai32またはu32
@must_use fn textureSampleCompare(t: texture_depth_cube_array,
                                  s: sampler_comparison,
                                  coords: vec3<f32>,
                                  array_index: A,
                                  depth_ref: f32) -> f32

パラメータ:

t サンプリング対象のデプステクスチャ
s sampler_comparison型。
coords サンプリングに使用するテクスチャ座標。
array_index サンプリング対象の0始まりのテクスチャ配列インデックス。
この値は必ず[0, textureNumLayers(t) - 1]の範囲にクランプされます。
depth_ref サンプリングされた深度値と比較する参照値。
offset サンプリング前に非正規化テクスチャ座標に適用されるオプションのテクセルオフセット。 このオフセットは、テクスチャラッピングモード適用前に適用されます。
offset式は必須定数式(例:vec2<i32>(1, 2))でなければなりません。
offset成分は必須-8以上7以下である必要があります。この範囲外はシェーダー生成エラーです。

戻り値:

範囲[0.0..1.0]の値。

各サンプリングされたテクセルは参照値と比較され、sampler_comparisonで定義された比較演算子により各テクセルごとに0または1が返されます。

サンプラーがバイリニアフィルタリングを使う場合は、返される値はこれらの値のフィルタ平均になり、それ以外の場合は単一テクセルの比較結果が返されます。

非一様な制御フローで呼び出した場合は不定値となります。

17.7.11. textureSampleCompareLevel

デプステクスチャをサンプリングし、サンプリングされた深度値を参照値と比較します。

パラメータ化 オーバーロード
@must_use fn textureSampleCompareLevel(t: texture_depth_2d,
                                       s: sampler_comparison,
                                       coords: vec2<f32>,
                                       depth_ref: f32) -> f32
@must_use fn textureSampleCompareLevel(t: texture_depth_2d,
                                       s: sampler_comparison,
                                       coords: vec2<f32>,
                                       depth_ref: f32,
                                       offset: vec2<i32>) -> f32
Ai32またはu32
@must_use fn textureSampleCompareLevel(t: texture_depth_2d_array,
                                       s: sampler_comparison,
                                       coords: vec2<f32>,
                                       array_index: A,
                                       depth_ref: f32) -> f32
Ai32またはu32
@must_use fn textureSampleCompareLevel(t: texture_depth_2d_array,
                                       s: sampler_comparison,
                                       coords: vec2<f32>,
                                       array_index: A,
                                       depth_ref: f32,
                                       offset: vec2<i32>) -> f32
@must_use fn textureSampleCompareLevel(t: texture_depth_cube,
                                       s: sampler_comparison,
                                       coords: vec3<f32>,
                                       depth_ref: f32) -> f32
Ai32またはu32
@must_use fn textureSampleCompareLevel(t: texture_depth_cube_array,
                                       s: sampler_comparison,
                                       coords: vec3<f32>,
                                       array_index: A,
                                       depth_ref: f32) -> f32

パラメータ:

t サンプリング対象のデプステクスチャ
s sampler_comparison型。
coords サンプリングに使用するテクスチャ座標。
array_index サンプリング対象の0始まりのテクスチャ配列インデックス。
この値は必ず[0, textureNumLayers(t) - 1]の範囲にクランプされます。
depth_ref サンプリングされた深度値と比較する参照値。
offset サンプリング前に非正規化テクスチャ座標に適用されるオプションのテクセルオフセット。 このオフセットは、テクスチャラッピングモード適用前に適用されます。
offset式は必須定数式(例:vec2<i32>(1, 2))でなければなりません。
offset成分は必須-8以上7以下である必要があります。この範囲外はシェーダー生成エラーです。

戻り値:

範囲[0.0..1.0]の値。

textureSampleCompareLevel関数はtextureSampleCompareと同じですが、以下の違いがあります:

17.7.12. textureSampleGrad

明示的な勾配を使ってテクスチャをサンプリングします。

パラメータ化 オーバーロード
@must_use fn textureSampleGrad(t: texture_2d<f32>,
                               s: sampler,
                               coords: vec2<f32>,
                               ddx: vec2<f32>,
                               ddy: vec2<f32>) -> vec4<f32>
@must_use fn textureSampleGrad(t: texture_2d<f32>,
                               s: sampler,
                               coords: vec2<f32>,
                               ddx: vec2<f32>,
                               ddy: vec2<f32>,
                               offset: vec2<i32>) -> vec4<f32>
Ai32またはu32
@must_use fn textureSampleGrad(t: texture_2d_array<f32>,
                               s: sampler,
                               coords: vec2<f32>,
                               array_index: A,
                               ddx: vec2<f32>,
                               ddy: vec2<f32>) -> vec4<f32>
Ai32またはu32
@must_use fn textureSampleGrad(t: texture_2d_array<f32>,
                               s: sampler,
                               coords: vec2<f32>,
                               array_index: A,
                               ddx: vec2<f32>,
                               ddy: vec2<f32>,
                               offset: vec2<i32>) -> vec4<f32>
Ttexture_3d<f32>またはtexture_cube<f32>
@must_use fn textureSampleGrad(t: T,
                               s: sampler,
                               coords: vec3<f32>,
                               ddx: vec3<f32>,
                               ddy: vec3<f32>) -> vec4<f32>
@must_use fn textureSampleGrad(t: texture_3d<f32>,
                               s: sampler,
                               coords: vec3<f32>,
                               ddx: vec3<f32>,
                               ddy: vec3<f32>,
                               offset: vec3<i32>) -> vec4<f32>
Ai32またはu32
@must_use fn textureSampleGrad(t: texture_cube_array<f32>,
                               s: sampler,
                               coords: vec3<f32>,
                               array_index: A,
                               ddx: vec3<f32>,
                               ddy: vec3<f32>) -> vec4<f32>

パラメータ:

t サンプリング対象のサンプルテクスチャ
s サンプラー
coords サンプリングに使用するテクスチャ座標。
array_index サンプリング対象の0始まりのテクスチャ配列インデックス。
この値は必ず[0, textureNumLayers(t) - 1]の範囲にクランプされます。
ddx サンプリング位置の計算に使用されるx方向の微分ベクトル。
ddy サンプリング位置の計算に使用されるy方向の微分ベクトル。
offset サンプリング前に非正規化テクスチャ座標に適用されるオプションのテクセルオフセット。 このオフセットは、テクスチャラッピングモード適用前に適用されます。
offset式は必須定数式(例:vec2<i32>(1, 2))でなければなりません。
offset成分は必須-8以上7以下である必要があります。この範囲外はシェーダー生成エラーです。

戻り値:

サンプリングされた値。

17.7.13. textureSampleLevel

明示的なミップレベルを指定してテクスチャをサンプリングします。

パラメータ化 オーバーロード
@must_use fn textureSampleLevel(t: texture_1d<f32>,
                                s: sampler,
                                coords: f32,
                                level: f32) -> vec4<f32>
@must_use fn textureSampleLevel(t: texture_2d<f32>,
                                s: sampler,
                                coords: vec2<f32>,
                                level: f32) -> vec4<f32>
@must_use fn textureSampleLevel(t: texture_2d<f32>,
                                s: sampler,
                                coords: vec2<f32>,
                                level: f32,
                                offset: vec2<i32>) -> vec4<f32>
Ai32またはu32
@must_use fn textureSampleLevel(t: texture_2d_array<f32>,
                                s: sampler,
                                coords: vec2<f32>,
                                array_index: A,
                                level: f32) -> vec4<f32>
Ai32またはu32
@must_use fn textureSampleLevel(t: texture_2d_array<f32>,
                                s: sampler,
                                coords: vec2<f32>,
                                array_index: A,
                                level: f32,
                                offset: vec2<i32>) -> vec4<f32>
Ttexture_3d<f32>またはtexture_cube<f32>
@must_use fn textureSampleLevel(t: T,
                                s: sampler,
                                coords: vec3<f32>,
                                level: f32) -> vec4<f32>
@must_use fn textureSampleLevel(t: texture_3d<f32>,
                                s: sampler,
                                coords: vec3<f32>,
                                level: f32,
                                offset: vec3<i32>) -> vec4<f32>
Ai32またはu32
@must_use fn textureSampleLevel(t: texture_cube_array<f32>,
                                s: sampler,
                                coords: vec3<f32>,
                                array_index: A,
                                level: f32) -> vec4<f32>
Li32またはu32
@must_use fn textureSampleLevel(t: texture_depth_2d,
                                s: sampler,
                                coords: vec2<f32>,
                                level: L) -> f32
Li32またはu32
@must_use fn textureSampleLevel(t: texture_depth_2d,
                                s: sampler,
                                coords: vec2<f32>,
                                level: L,
                                offset: vec2<i32>) -> f32
Ai32またはu32
Li32またはu32
@must_use fn textureSampleLevel(t: texture_depth_2d_array,
                                s: sampler,
                                coords: vec2<f32>,
                                array_index: A,
                                level: L) -> f32
Ai32またはu32
Li32またはu32
@must_use fn textureSampleLevel(t: texture_depth_2d_array,
                                s: sampler,
                                coords: vec2<f32>,
                                array_index: A,
                                level: L,
                                offset: vec2<i32>) -> f32
Li32またはu32
@must_use fn textureSampleLevel(t: texture_depth_cube,
                                s: sampler,
                                coords: vec3<f32>,
                                level: L) -> f32
Ai32またはu32
Li32またはu32
@must_use fn textureSampleLevel(t: texture_depth_cube_array,
                                s: sampler,
                                coords: vec3<f32>,
                                array_index: A,
                                level: L) -> f32

パラメータ:

t サンプリング対象のサンプルテクスチャまたはデプステクスチャ
s サンプラー型。
coords サンプリングに使用するテクスチャ座標。
array_index サンプリング対象の0始まりのテクスチャ配列インデックス。
この値は必ず[0, textureNumLayers(t) - 1]の範囲にクランプされます。
level ミップレベル。レベル0はテクスチャのフルサイズ。 levelf32の場合、フォーマットがフィルタ可能なら二つのレベル間で補間されることがあります。詳細は Texture Format Capabilities参照。
offset サンプリング前に非正規化テクスチャ座標に適用されるオプションのテクセルオフセット。 このオフセットは、テクスチャラッピングモード適用前に適用されます。
offset式は必須定数式(例:vec2<i32>(1, 2))でなければなりません。
offset成分は必須-8以上7以下である必要があります。この範囲外はシェーダー生成エラーです。

戻り値:

サンプリングされた値。

17.7.14. textureSampleBaseClampToEdge

テクスチャビューのベースレベルをサンプリングし、 テクスチャ座標は以下の通りエッジにクランプされます。

パラメータ化 オーバーロード
Ttexture_2d<f32>またはtexture_external
@must_use fn textureSampleBaseClampToEdge(t: T,
                                          s: sampler,
                                          coords: vec2<f32>) -> vec4<f32>

パラメータ:

t サンプリング対象のサンプルテクスチャまたは外部テクスチャ
s サンプラー型。
coords サンプリングに使用するテクスチャ座標。

サンプリング前に、指定した座標は必ず以下の矩形範囲にクランプされます:

[ half_texel, 1 - half_texel ]

ここで

half_texel = vec2(0.5) / vec2<f32>(textureDimensions(t))

注: ハーフテクセル調整により、 サンプラーのアドレス指定フィルタ モードに関わらず、 ラッピングが発生しません。 つまり、エッジ付近でサンプリングすると、サンプルされるテクセルはそのエッジ上または隣接する位置となり、反対側のエッジから選ばれることはありません。

戻り値:

サンプリングされた値。

17.7.15. textureStore

テクスチャに単一のテクセルを書き込みます。

パラメータ化 オーバーロード
Fテクセルフォーマット
Ci32またはu32
AMwriteまたはread_write
CFはストレージテクセルフォーマットFに依存します。 テクセルフォーマット表で テクセルフォーマットとチャンネルフォーマットの対応を確認してください。
fn textureStore(t: texture_storage_1d<F,AM>,
                coords: C,
                value: vec4<CF>)
Fテクセルフォーマット
Ci32またはu32
AMwriteまたはread_write
CFはストレージテクセルフォーマットFに依存します。 テクセルフォーマット表で テクセルフォーマットとチャンネルフォーマットの対応を確認してください。
fn textureStore(t: texture_storage_2d<F,AM>,
                coords: vec2<C>,
                value: vec4<CF>)
Fテクセルフォーマット
Ci32またはu32
AMwriteまたはread_write
Ai32またはu32
CFはストレージテクセルフォーマットFに依存します。 テクセルフォーマット表で テクセルフォーマットとチャンネルフォーマットの対応を確認してください。
fn textureStore(t: texture_storage_2d_array<F,AM>,
                coords: vec2<C>,
                array_index: A,
                value: vec4<CF>)
Fテクセルフォーマット
Ci32またはu32
AMwriteまたはread_write
CFはストレージテクセルフォーマットFに依存します。 テクセルフォーマット表で テクセルフォーマットとチャンネルフォーマットの対応を確認してください。
fn textureStore(t: texture_storage_3d<F,AM>,
                coords: vec3<C>,
                value: vec4<CF>)

パラメータ:

t 書き込み専用ストレージテクスチャまたは 読書き可能ストレージテクスチャ
coords 0始まりのテクセル座標。
array_index 0始まりのテクスチャ配列インデックス。
value 新しいテクセル値。 value逆チャンネル伝達関数で変換されます。

注:

論理テクセルアドレスが不正な場合:

論理テクセルアドレスが不正な場合、組み込み関数は必ず実行されません。

17.8. アトミック組み込み関数

アトミック組み込み関数は、アトミックなオブジェクトの読み取り/書き込み/読取-修正-書き込みに使用できます。これらは§ 6.2.8 アトミック型で許可された唯一の操作です。

すべてのアトミック組み込み関数はrelaxedメモリ順序を使用します。これは、同期と順序の保証が同じメモリ位置で動作するアトミック操作間にのみ適用されることを意味します。アトミックと非アトミックのメモリアクセス間、または異なるメモリ位置で動作するアトミックアクセス間には同期や順序の保証はありません。

アトミック組み込み関数は絶対に頂点シェーダーステージで使用してはいけません。

すべてのアトミック組み込み関数におけるatomic_ptrパラメータのアドレス空間ASは、必ずstorageまたはworkgroupでなければなりません。

T必ずu32またはi32でなければなりません。

17.8.1. atomicLoad

fn atomicLoad(atomic_ptr: ptr<AS, atomic<T>, read_write>) -> T

atomic_ptrで指された値をアトミックにロードして返します。オブジェクト自体は変更しません。

17.8.2. atomicStore

fn atomicStore(atomic_ptr: ptr<AS, atomic<T>, read_write>, v: T)

vの値をatomic_ptrで指されたアトミックオブジェクトにアトミックに格納します。

17.8.3. アトミック読取-修正-書き込み演算・論理関数

各関数は以下の手順をアトミックに行います:

  1. atomic_ptrで指された元の値をロードする。

  2. 関数名から指定された操作(例: max)を値vとともに実行し、新しい値を取得する。

  3. 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演算をアトミックに行い、操作前にアトミックオブジェクトに格納されていた元の値を返します。

例: 関数としてのアトミックなビット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演算をアトミックに行い、操作前にアトミックオブジェクトに格納されていた元の値を返します。

例: 関数としてのアトミックなビット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演算をアトミックに行い、操作前にアトミックオブジェクトに格納されていた元の値を返します。

例: 関数としてのアトミックなビット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型で値を明示的に宣言することはできませんが、型推論は可能です。

次のステップをアトミックに実行します:

  1. atomic_ptrが指す元の値をロードします。

  2. 元の値とcmpの値を等価演算で比較します。

  3. 等価比較の結果がtrueの場合のみ、値vを格納します。

2つのメンバーからなる構造体を返します。最初のメンバーold_valueは操作前のアトミックオブジェクトの元の値で、2番目のメンバーexchangedは比較が成功したかどうかを示します。

例: 関数としてのアトミックな比較交換操作
// すべての操作はアトミックに実行されます
fn atomicCompareExchangeWeak(atomic_ptr: ptr<AS, atomic<T>, read_write>, cmp : T, v : T) ->
  _atomic_compare_exchange_result<T> {
  let old = *atomic_ptr;
  // この比較は偽陽性で失敗する可能性があります。
  let comparison = old == cmp;
  if comparison {
    *atomic_ptr = v;
  }
  return _atomic_compare_exchange_result<T>(old, comparison);
}

注: 一部の実装では等価比較が偽陽性で失敗する場合があります。つまり、結果ベクトルの第2成分がfalseとなる場合でも、第1成分がcmpと等しいことがあります。

17.9. データパッキング組み込み関数

データパッキング組み込み関数は、WGSLの型と直接対応しないデータフォーマットを使用して値をエンコードするために利用できます。 これにより、多くの密集した値をメモリに書き込むことが可能となり、シェーダのメモリ帯域幅要求を削減できます。

各組み込み関数は、複数の入力値にチャネル転送関数を適用し、その結果を一つの出力値にまとめます。

注: unorm値のパッキングでは、正規化された浮動小数点値は区間[0.0, 1.0]にあります。

注: snorm値のパッキングでは、正規化された浮動小数点値は区間[-1.0, 1.0]にあります。

17.9.1. pack4x8snorm

オーバーロード
@const @must_use fn pack4x8snorm(e: vec4<f32>) -> u32
説明 4つの正規化された浮動小数点値を8ビット符号付き整数に変換し、それらを1つのu32値にまとめます。

入力の各成分e[i]は、8ビット2の補数整数値 ⌊ 0.5 + 127 × min(1, max(-1, e[i])) ⌋に変換され、 結果の8 × iから8 × i + 7までのビットに配置されます。

17.9.2. pack4x8unorm

オーバーロード
@const @must_use fn pack4x8unorm(e: vec4<f32>) -> u32
説明 4つの正規化された浮動小数点値を8ビット符号なし整数に変換し、それらを1つのu32値にまとめます。

入力の各成分e[i]は、8ビット符号なし整数値 ⌊ 0.5 + 255 × min(1, max(0, e[i])) ⌋に変換され、 結果の8 × iから8 × i + 7までのビットに配置されます。

17.9.3. pack4xI8

オーバーロード
@const @must_use fn pack4xI8(e: vec4<i32>) -> u32
説明 eの各コンポーネントの下位8ビットをu32値にパックし、未使用のビットはすべて捨てます。

入力のコンポーネント e[i] は、結果の 8 × i から 8 × i + 7 のビットにマッピングされます。

17.9.4. pack4xU8

オーバーロード
@const @must_use fn pack4xU8(e: vec4<u32>) -> u32
説明 eの各コンポーネントの下位8ビットをu32値にパックし、未使用のビットはすべて捨てます。

入力のコンポーネント e[i] は、結果の 8 × i から 8 × i + 7 のビットにマッピングされます。

17.9.5. pack4xI8Clamp

オーバーロード
@const @must_use fn pack4xI8Clamp(e: vec4<i32>) -> u32
説明 e の各コンポーネントを範囲 [-128, 127] にクランプし、その後各コンポーネントの下位8ビットを u32 値にパックします。

入力のコンポーネント e[i] は、結果の 8 × i から 8 × i + 7 のビットにマッピングされます。

17.9.6. pack4xU8Clamp

オーバーロード
@const @must_use fn pack4xU8Clamp(e: vec4<u32>) -> u32
説明 e の各コンポーネントを [0, 255] の範囲でクランプし、その後各コンポーネントの下位8ビットを u32 値にパックします。

入力のコンポーネント e[i] は、結果の 8 × i から 8 × i + 7 のビットにマッピングされます。

17.9.7. pack2x16snorm

オーバーロード
@const @must_use fn pack2x16snorm(e: vec2<f32>) -> u32
説明 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

オーバーロード
@const @must_use fn pack2x16unorm(e: vec2<f32>) -> u32
説明 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

オーバーロード
@const @must_use fn pack2x16float(e: vec2<f32>) -> u32
説明 2つの浮動小数点値を半精度浮動小数点数に変換し、それらを1つのu32値にまとめます。
入力の各成分e[i]IEEE-754 binary16 値に変換され、 結果の16 × iから16 × i + 15までのビットに配置されます。 § 15.7.6 浮動小数点変換も参照してください。

もしe[0]またはe[1]がbinary16の有限範囲外の場合:

17.10. データアンパック組み込み関数

データアンパック組み込み関数は、WGSLの型と直接対応しないデータフォーマット内の値をデコードするために利用できます。 これにより、プログラムはメモリから多くの密集した値を読み取ることができ、シェーダのメモリ帯域幅の要求を削減できます。

各組み込み関数は入力値をチャネルに分割し、それぞれにチャネル転送関数を適用します。

注: unorm値のアンパックでは、正規化された浮動小数点の結果は区間[0.0, 1.0]にあります。

注: snorm値のアンパックでは、正規化された浮動小数点の結果は区間[-1.0, 1.0]にあります。

17.10.1. unpack4x8snorm

オーバーロード
@const @must_use fn unpack4x8snorm(e: u32) -> vec4<f32>
説明 32ビット値を4つの8ビットチャンクに分解し、各チャンクを符号付き正規化浮動小数点値として再解釈します。
結果の成分iはmax(v ÷ 127, -1)です。ここでveの8×iから8×i + 7のビットを2の補数符号付き整数として解釈した値です。

17.10.2. unpack4x8unorm

オーバーロード
@const @must_use fn unpack4x8unorm(e: u32) -> vec4<f32>
説明 32ビット値を4つの8ビットチャンクに分解し、各チャンクを符号なし正規化浮動小数点値として再解釈します。
結果の成分iv ÷ 255です。ここでveの8×iから8×i + 7のビットを符号なし整数として解釈した値です。

17.10.3. unpack4xI8

オーバーロード
@const @must_use fn unpack4xI8(e: u32) -> vec4<i32>
説明 eは4つの8ビット符号付き整数成分を持つベクトルとして解釈されます。eを符号拡張付きのvec4<i32>にアンパックします。

17.10.4. unpack4xU8

オーバーロード
@const @must_use fn unpack4xU8(e: u32) -> vec4<u32>
説明 eは4つの8ビット符号なし整数成分を持つベクトルとして解釈されます。eをゼロ拡張付きのvec4<u32>にアンパックします。

17.10.5. unpack2x16snorm

オーバーロード
@const @must_use fn unpack2x16snorm(e: u32) -> vec2<f32>
説明 32ビット値を2つの16ビットチャンクに分解し、各チャンクを符号付き正規化浮動小数点値として再解釈します。
結果の成分iはmax(v ÷ 32767, -1)です。ここでveの16×iから16×i + 15のビットを2の補数符号付き整数として解釈した値です。

17.10.6. unpack2x16unorm

オーバーロード
@const @must_use fn unpack2x16unorm(e: u32) -> vec2<f32>
説明 32ビット値を2つの16ビットチャンクに分解し、各チャンクを符号なし正規化浮動小数点値として再解釈します。
結果の成分iv ÷ 65535です。ここでveの16×iから16×i + 15のビットを符号なし整数として解釈した値です。

17.10.7. unpack2x16float

オーバーロード
@const @must_use fn unpack2x16float(e: u32) -> vec2<f32>
説明 32ビット値を2つの16ビットチャンクに分解し、各チャンクを浮動小数点値として再解釈します。
結果の成分ivのf32表現です。ここでveの16×iから16×i + 15のビットをIEEE-754 binary16値として解釈したものです。 § 15.7.6 浮動小数点変換も参照してください。

17.11. 同期組み込み関数

すべての同期関数は制御バリアを Acquire/Release メモリ順序で実行します。 つまり、すべての同期関数と、影響を受けるメモリおよびアトミック操作は、同期関数に対してプログラム順序で並べられます。 さらに、同期関数よりプログラム順序で前にある影響を受けるメモリやアトミック操作は、同期関数より後にワークグループのメンバーによって実行される任意の影響を受けるメモリやアトミック操作の前に、ワークグループ内のすべての他のスレッドに対して可視でなければなりません。

すべての同期関数はWorkgroupメモリスコープを使用します。
すべての同期関数はWorkgroup実行スコープを持ちます。
すべての同期関数は必須コンピュートシェーダステージのみで使用しなければなりません。 すべての同期関数は必須一様制御フロー内でのみ呼び出さなければなりません。

17.11.1. storageBarrier

オーバーロード
fn storageBarrier()
説明 制御バリア同期関数を実行し、 storageアドレス空間の メモリおよびアトミック操作に影響します。

17.11.2. textureBarrier

オーバーロード
fn textureBarrier()
説明 制御バリア同期関数を実行し、 handleアドレス空間の メモリ操作に影響します。

17.11.3. workgroupBarrier

オーバーロード
fn workgroupBarrier()
説明 制御バリア同期関数を実行し、 workgroupアドレス空間の メモリおよびアトミック操作に影響します。

17.11.4. workgroupUniformLoad

オーバーロード
@must_use fn workgroupUniformLoad(p : ptr<workgroup, T>) -> T
パラメータ化 T具体的構築可能型です。
説明 pが指す値をワークグループ内のすべての呼び出しに返します。 戻り値は一様です。 p必須一様値でなければなりません。

制御バリア同期関数を実行し、 workgroupアドレス空間の メモリおよびアトミック操作に影響します。

オーバーロード
@must_use fn workgroupUniformLoad(p : ptr<workgroup, atomic<T>, read_write>) -> T
説明 pが指す値をアトミックにロードし、ワークグループ内のすべての呼び出しに返します。 戻り値は一様です。 p必須一様値でなければなりません。

制御バリア同期関数を実行し、 workgroupアドレス空間の メモリおよびアトミック操作に影響します。

17.12. サブグループ組み込み関数

§ 15.6.3 サブグループ操作を参照。

これらの関数の呼び出しは:

注: コンピュートシェーダステージの場合、 一様制御フローのスコープはワークグループです。 フラグメントシェーダステージの場合、 一様制御フローのスコープは描画コマンドです。 これらのスコープはどちらもサブグループよりも大きいです。

17.12.1. subgroupAdd

オーバーロード
@must_use fn subgroupAdd(e : T) -> T
前提条件 T具体的数値スカラーまたは数値ベクトルです
説明 集約(リダクション)操作。

eの全てのアクティブな呼び出しの合計を サブグループ内で返します。

17.12.1.1. subgroupExclusiveAdd
オーバーロード
@must_use fn subgroupExclusiveAdd(e : T) -> T
前提条件 T具体的数値スカラーまたは数値ベクトルです
説明 除外プレフィックススキャン操作(エクスクルーシブスキャン)。

eの全てのアクティブな呼び出しのうち、 サブグループ内で現在の呼び出しIDより小さい サブグループ呼び出しIDを持つ呼び出しの合計を返します。

アクティブな呼び出しの中で最もIDが小さい呼び出しに対して返る値はT(0)です。

17.12.1.2. subgroupInclusiveAdd
オーバーロード
@must_use fn subgroupInclusiveAdd(e : T) -> T
前提条件 T具体的数値スカラーまたは数値ベクトルです
説明 包含プレフィックススキャン操作(インクルーシブスキャン)。

eの全てのアクティブな呼び出しのうち、 サブグループ内で現在の呼び出しID以下の サブグループ呼び出しIDを持つ呼び出しの合計を返します。

注: subgroupExclusiveAdd(x) + xと同等です。

17.12.2. subgroupAll

オーバーロード
@must_use fn subgroupAll(e : bool) -> bool
説明 アクティブな呼び出しのすべてでetrueの場合にtrueを返します。対象はサブグループです。

17.12.3. subgroupAnd

オーバーロード
@must_use fn subgroupAnd(e : T) -> T
前提条件 Tはi32, u32, vecN<i32>, またはvecN<u32>です
説明 集約(リダクション)操作。

アクティブな呼び出しのすべてに対して、eのビットごとのAND(&)を返します。対象はサブグループです。

17.12.4. subgroupAny

オーバーロード
@must_use fn subgroupAny(e : bool) -> bool
説明 アクティブな呼び出しのいずれかでetrueの場合にtrueを返します。対象はサブグループです。

17.12.5. subgroupBallot

オーバーロード
@must_use fn subgroupBallot(pred : bool) -> vec4<u32>
説明 アクティブな呼び出しのうち、predtrueであるもののビットマスクを サブグループ内で返します。

戻り値のx成分は呼び出しID 0〜31を含みます。
y成分は呼び出しID 32〜63を含みます。
z成分は呼び出しID 64〜95を含みます。
w成分は呼び出しID 96〜127を含みます。

各成分内では、IDはビット位置で昇順です(例:ID 32はy成分のビット位置0)。

17.12.6. subgroupBroadcast

オーバーロード
@must_use fn subgroupBroadcast(e : T, id : I) -> T
前提条件 T具体的数値スカラーまたは数値ベクトル
Iu32 または i32です
説明 サブグループ呼び出しIDidと一致する呼び出しのeの値を、サブグループ内のすべてのアクティブな呼び出しに返します。

idは範囲[0,128)内の定数式でなければなりません。

idアクティブ呼び出しを選択しない場合は動的エラーです。

注: 非定数のidが必要な場合は subgroupShuffleを使用してください。

17.12.6.1. subgroupBroadcastFirst
オーバーロード
@must_use fn subgroupBroadcastFirst(e : T) -> T
前提条件 T具体的数値スカラーまたは数値ベクトルです
説明 アクティブな呼び出しの中で最も小さいサブグループ呼び出しIDを持つ呼び出しのeの値を、サブグループ内のすべてのアクティブな呼び出しに返します。

17.12.7. subgroupElect

オーバーロード
@must_use fn subgroupElect() -> bool
説明 現在の呼び出しがアクティブな呼び出しの中で最も小さいサブグループ呼び出しIDを持つ場合trueを返します。対象はサブグループです。

17.12.8. subgroupMax

オーバーロード
@must_use fn subgroupMax(e : T) -> T
前提条件 T具体的数値スカラーまたは数値ベクトルです
説明 集約(リダクション)操作。

アクティブな呼び出しのすべてのうち、eの最大値を返します。対象はサブグループです。

17.12.9. subgroupMin

オーバーロード
@must_use fn subgroupMin(e : T) -> T
前提条件 T具体的数値スカラーまたは数値ベクトルです
説明 集約(リダクション)操作。

アクティブな呼び出しのすべてのうち、eの最小値を返します。対象はサブグループです。

17.12.10. subgroupMul

オーバーロード
@must_use fn subgroupMul(e : T) -> T
前提条件 T具体的数値スカラーまたは数値ベクトルです
説明 集約(リダクション)操作。

アクティブな呼び出し全体でeの積を サブグループ内で返します。

17.12.10.1. subgroupExclusiveMul
オーバーロード
@must_use fn subgroupExclusiveMul(e : T) -> T
前提条件 T具体的数値スカラーまたは数値ベクトルです
説明 除外プレフィックススキャン操作(エクスクルーシブスキャン)。

アクティブな呼び出しのうち、現在の呼び出しIDより小さい サブグループ呼び出しIDを持つ呼び出し全体でeの積を サブグループ内で返します。

アクティブな呼び出しのうち最もIDが小さい呼び出しに対して返る値はT(1)です。

17.12.10.2. subgroupInclusiveMul
オーバーロード
@must_use fn subgroupInclusiveMul(e : T) -> T
前提条件 T具体的数値スカラーまたは数値ベクトルです
説明 包含プレフィックススキャン操作(インクルーシブスキャン)。

アクティブな呼び出しのうち、現在の呼び出しID以下の サブグループ呼び出しIDを持つ呼び出し全体でeの積を サブグループ内で返します。

注: subgroupExclusiveMul(x) * xと同等です。

17.12.11. subgroupOr

オーバーロード
@must_use fn subgroupOr(e : T) -> T
前提条件 Tはi32, u32, vecN<i32>, またはvecN<u32>です
説明 集約(リダクション)操作。

アクティブな呼び出し全体でeのビットごとのOR(|)を サブグループ内で返します。

17.12.12. subgroupShuffle

オーバーロード
@must_use fn subgroupShuffle(e : T, id : I) -> T
前提条件 T具体的数値スカラーまたは数値ベクトル
Iu32 または i32です
説明 サブグループ呼び出しIDidと一致する呼び出しのeを返します。

もしidが範囲[0,128)外の場合:

idアクティブな呼び出しを選択しない場合、 不定値が返されます。

17.12.12.1. subgroupShuffleDown
オーバーロード
@must_use fn subgroupShuffleDown(e : T, delta : u32) -> T
前提条件 T具体的数値スカラーまたは数値ベクトルです
説明 現在の呼び出しについて、サブグループ呼び出しIDsubgroup_invocation_id + deltaと一致する呼び出しのeを返します。

もしdeltaが127より大きい場合:

delta一様値でない場合、 subgroup_uniformity 診断トリガーされます。 また、subgroup_invocation_id + deltaアクティブな呼び出しを選択しない場合やdeltaがサブグループ内で一様値でない場合は 不定値が返されます。

17.12.12.2. subgroupShuffleUp
オーバーロード
@must_use fn subgroupShuffleUp(e : T, delta : u32) -> T
前提条件 T具体的数値スカラーまたは数値ベクトルです
説明 現在の呼び出しについて、サブグループ呼び出しIDsubgroup_invocation_id - deltaと一致する呼び出しのeを返します。

もしdeltaが127より大きい場合:

delta一様値でない場合、 subgroup_uniformity 診断トリガーされます。 また、subgroup_invocation_id - deltaアクティブな呼び出しを選択しない場合やdeltaがサブグループ内で一様値でない場合は 不定値が返されます。

17.12.12.3. subgroupShuffleXor
オーバーロード
@must_use fn subgroupShuffleXor(e : T,  mask : u32) -> T
前提条件 T具体的数値スカラーまたは数値ベクトルです
説明 現在の呼び出しについて、サブグループ呼び出しIDsubgroup_invocation_id ^ maskと一致する呼び出しのeを返します。

もしmaskが127より大きい場合:

mask一様値でない場合、 subgroup_uniformity 診断トリガーされます。 また、maskアクティブな呼び出しを選択しない場合やmaskがサブグループ内で一様値でない場合は 不定値が返されます。

17.12.13. subgroupXor

オーバーロード
@must_use fn subgroupXor(e : T) -> T
前提条件 Tはi32, u32, vecN<i32>, またはvecN<u32>です
説明 集約(リダクション)操作。

アクティブな呼び出し全体でeのビットごとのXOR(^)を サブグループ内で返します。

17.13. クアッド操作

§ 15.6.4 クアッド操作を参照。

これらの関数の呼び出しは:

注: コンピュートシェーダステージの場合、 一様制御フローのスコープはワークグループです。 フラグメントシェーダステージの場合、 一様制御フローのスコープは描画コマンドです。 これらのスコープはどちらもクアッドよりも大きいです。

17.13.1. quadBroadcast

オーバーロード
@must_use fn quadBroadcast(e : T, id : I) -> T
前提条件 T具体的数値スカラーまたは数値ベクトル
Iu32またはi32です
説明 クアッド呼び出しIDidと一致する呼び出しのeの値を、クアッド内のすべてのアクティブな呼び出しに返します。

idは範囲[0,4)内の定数式でなければなりません。

idアクティブな呼び出しを選択しない場合、 不定値が返されます。

注: subgroupBroadcastとは異なり、現時点では非定数の代替手段はありません。

17.13.2. quadSwapDiagonal

オーバーロード
@must_use fn quadSwapDiagonal(e : T) -> T
前提条件 T具体的数値スカラーまたは数値ベクトルです
説明 クアッド内で対角にある呼び出しのeの値を返します。 すなわち:
  • ID 0 と 3 が入れ替わります。

  • ID 1 と 2 が入れ替わります。

17.13.3. quadSwapX

オーバーロード
@must_use fn quadSwapX(e : T) -> T
前提条件 T具体的数値スカラーまたは数値ベクトルです
説明 クアッド内で同じX次元を共有する呼び出しのeの値を返します。 すなわち:
  • ID 0 と 1 が入れ替わります。

  • ID 2 と 3 が入れ替わります。

17.13.4. quadSwapY

オーバーロード
@must_use fn quadSwapY(e : T) -> T
前提条件 T具体的数値スカラーまたは数値ベクトルです
説明 クアッド内で同じY次元を共有する呼び出しのeの値を返します。 すなわち:
  • ID 0 と 2 が入れ替わります。

  • ID 1 と 3 が入れ替わります。

18. 再帰下降構文解析用の文法

この章は規範的ではありません。

WGSLの文法はLALR(1)パーサに適した形式で定義されています。 実装によっては、再帰下降パーサを使いたい場合もあります。

規範的な文法は、再帰下降パーサには直接利用できません。なぜなら、いくつかの規則が左再帰的だからです。 文法規則が直接左再帰であるとは、定義されている非終端記号がその生成規則の最初に現れる場合を指します。

以下はWGSL文法ですが、機械的に次のように変換されています:

ただし、LL(1)ではありません。 非終端記号によっては、複数の生成規則が共通の先読み集合を持ちます。 例として、attribute 非終端記号のすべての生成規則は attr トークンで始まります。 より微妙な例としては global_decl で、3つの生成規則が attribute * 句で始まり、 その後 fn, override, var トークンで区別されます。

簡潔さのため、多くのトークン定義は繰り返されません。 トークン定義は仕様書の主部のものを利用してください。

additive_operator:

| '+'

| '-'

argument_expression_list:

| '(' ( expression ( ',' expression )* ',' ? )? ')'

assignment_statement/0.1:

| compound_assignment_operator

| '='

attribute:

| compute_attr

| const_attr

| fragment_attr

| interpolate_attr

| invariant_attr

| must_use_attr

| vertex_attr

| workgroup_size_attr

| '@' 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 ',' ? ')'

bitwise_expression.post.unary_expression:

| '&' unary_expression ( '&' unary_expression )*

| '^' unary_expression ( '^' unary_expression )*

| '|' unary_expression ( '|' unary_expression )*

bool_literal:

| 'false'

| 'true'

builtin_value_name: ident_pattern_token
case_selector:

| expression

| 'default'

component_or_swizzle_specifier:

| '.' member_ident component_or_swizzle_specifier ?

| '.' swizzle_name component_or_swizzle_specifier ?

| '[' expression ']' component_or_swizzle_specifier ?

compound_assignment_operator:

| shift_left_assign

| shift_right_assign

| '%='

| '&='

| '*='

| '+='

| '-='

| '/='

| '^='

| '|='

compound_statement:

| attribute * '{' statement * '}'

compute_attr:

| '@' 'compute'

const_attr:

| '@' 'const'

core_lhs_expression:

| ident

| '(' lhs_expression ')'

decimal_float_literal:

| /0[fh]/

| /[0-9]*\.[0-9]+([eE][+-]?[0-9]+)?[fh]?/

| /[0-9]+[eE][+-]?[0-9]+[fh]?/

| /[0-9]+\.[0-9]*([eE][+-]?[0-9]+)?[fh]?/

| /[1-9][0-9]*[fh]/

decimal_int_literal:

| /0[iu]?/

| /[1-9][0-9]*[iu]?/

diagnostic_control:

| '(' ident_pattern_token ',' diagnostic_rule_name ',' ? ')'

diagnostic_rule_name:

| ident_pattern_token

| ident_pattern_token '.' ident_pattern_token

expression:

| 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 )*

float_literal:

| decimal_float_literal

| hex_float_literal

for_init:

| ident func_call_statement.post.ident

| variable_or_value_statement

| variable_updating_statement

for_update:

| ident func_call_statement.post.ident

| variable_updating_statement

fragment_attr:

| '@' 'fragment'

func_call_statement.post.ident:

| template_elaborated_ident.post.ident '(' ( expression ( ',' expression )* ',' ? )? ')'

global_assert:

| 'const_assert' ';'

global_decl:

| 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 )* ',' ? '}'

global_directive:

| 'diagnostic' '(' ident_pattern_token ',' diagnostic_rule_name ',' ? ')' ';'

| 'enable' ident_pattern_token ( ',' ident_pattern_token )* ',' ? ';'

| 'requires' ident_pattern_token ( ',' ident_pattern_token )* ',' ? ';'

global_value_decl:

| attribute * 'override' optionally_typed_ident ( '=' expression )?

| 'const' optionally_typed_ident '=' expression

hex_float_literal:

| /0[xX][0-9a-fA-F]*\.[0-9a-fA-F]+([pP][+-]?[0-9]+[fh]?)?/

| /0[xX][0-9a-fA-F]+[pP][+-]?[0-9]+[fh]?/

| /0[xX][0-9a-fA-F]+\.[0-9a-fA-F]*([pP][+-]?[0-9]+[fh]?)?/

ident:

| ident_pattern_token

int_literal:

| decimal_int_literal

| hex_int_literal

interpolate_attr:

| '@' 'interpolate' '(' ident_pattern_token ',' ? ')'

| '@' 'interpolate' '(' ident_pattern_token ',' ident_pattern_token ',' ? ')'

invariant_attr:

| '@' 'invariant'

lhs_expression:

| core_lhs_expression component_or_swizzle_specifier ?

| '&' lhs_expression

| '*' lhs_expression

literal:

| bool_literal

| float_literal

| int_literal

member_ident: ident_pattern_token
multiplicative_operator:

| '%'

| '*'

| '/'

must_use_attr:

| '@' 'must_use'

optionally_typed_ident:

| ident ( ':' type_specifier )?

param:

| attribute * ident ':' type_specifier

primary_expression:

| ident template_elaborated_ident.post.ident

| ident template_elaborated_ident.post.ident argument_expression_list

| literal

| '(' expression ')'

relational_expression.post.unary_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

shift_expression.post.unary_expression:

| ( multiplicative_operator unary_expression )* ( additive_operator unary_expression ( multiplicative_operator unary_expression )* )*

| shift_left unary_expression

| shift_right unary_expression

statement:

| 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

| 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 ? ';'

switch_clause:

| 'case' case_selector ( ',' case_selector )* ',' ? ':' ? compound_statement

| 'default' ':' ? compound_statement

swizzle_name:

| /[rgba]/

| /[rgba][rgba]/

| /[rgba][rgba][rgba]/

| /[rgba][rgba][rgba][rgba]/

| /[xyzw]/

| /[xyzw][xyzw]/

| /[xyzw][xyzw][xyzw]/

| /[xyzw][xyzw][xyzw][xyzw]/

template_arg_expression: expression
template_elaborated_ident.post.ident:

| ( _template_args_start template_arg_expression ( ',' expression )* ',' ? _template_args_end )?

translation_unit:

| global_directive * ( global_decl | global_assert | ';' ) *

translation_unit/0.1/0/0.0:

| global_assert

| global_decl

| ';'

type_specifier:

| ident ( _template_args_start template_arg_expression ( ',' expression )* ',' ? _template_args_end )?

unary_expression:

| primary_expression component_or_swizzle_specifier ?

| '!' unary_expression

| '&' unary_expression

| '*' unary_expression

| '-' unary_expression

| '~' unary_expression

variable_decl:

| 'var' ( _template_args_start expression ( ',' expression )* ',' ? _template_args_end )? optionally_typed_ident

variable_or_value_statement:

| variable_decl

| variable_decl '=' expression

| 'const' optionally_typed_ident '=' expression

| 'let' optionally_typed_ident '=' expression

variable_updating_statement:

| lhs_expression ( '=' | compound_assignment_operator ) expression

| lhs_expression '++'

| lhs_expression '--'

| '_' '=' expression

vertex_attr:

| '@' 'vertex'

workgroup_size_attr:

| '@' 'workgroup_size' '(' expression ',' ? ')'

| '@' 'workgroup_size' '(' expression ',' expression ',' ? ')'

| '@' 'workgroup_size' '(' expression ',' expression ',' expression ',' ? ')'

付録A: text/wgsl メディアタイプ

Internet Assigned Numbers Authority (IANA) はメディアタイプのレジストリを管理しています。詳細は [IANA-MEDIA-TYPES] をご覧ください。

以下は WGSL モジュール向け text/wgsl メディアタイプの定義です。 これは IANA に登録されており、 https://www.iana.org/assignments/media-types/text/wgsl に掲載されています。

タイプ名

text

サブタイプ名

wgsl

必須パラメータ

N/A

オプションパラメータ

なし

エンコーディングに関する考慮事項

binary

WGSLはUTF-8エンコーディングを使用するUnicodeテキストであり、バイトオーダーマーク(BOM)はありません。 詳細は § 3 テキスト構造 を参照してください。

セキュリティに関する考慮事項

WebGPU Shading Language (WGSL) はGPUコードのためのプログラミング言語であり、WebGPU API のコンテキストで実行されます。セキュリティに関する考慮事項については [WebGPU] の2.1節をご覧ください。 プライバシーに関する考慮事項については [WebGPU] の2.2節をご覧ください。

相互運用性に関する考慮事項

WebGPUの実装ごとに異なる機能を持つ場合があり、これらの違いはWGSLプログラムで利用できる機能に影響を及ぼします。詳細は [WebGPU] の3.6節や、 § 4.1.2 言語拡張 を参照してください。

本登録はWGSLの後続版にも適用されることが期待されており、公開仕様の参照も随時更新される可能性があります。このような期待はメディアタイプ登録の中では異例ですが、業界慣習には合致します。

公開仕様

WebGPU Shading Language

このメディアタイプを利用するアプリケーション

WebGPUの実装。これにはWebブラウザも含まれると想定されます。

フラグメント識別子の考慮事項

なし

追加情報

マジックナンバー: なし

ファイル拡張子: .wgsl

Macintoshファイルタイプコード: 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

適合性

文書の慣例

適合性の要件は、記述的な主張とRFC 2119の用語を組み合わせて表現されています。 規範的な部分で使われる “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, “OPTIONAL” というキーワードは、 RFC 2119で説明されている通りに解釈してください。 ただし、可読性のため、この仕様書ではこれらの語はすべて大文字では記載されていません。

この仕様書のすべての本文は規範的ですが、明示的に非規範的と記載された章、例、および注記は除きます。 [RFC2119]

この仕様書における例は、「例えば」という語で始まるか、class="example"で規範的な本文と区別されます。 例:

これは参考例の例です。

参考注記は「注」と始まり、class="note"で規範的な本文と区別されます。 例:

注:これは参考注記です。

適合性のあるアルゴリズム

アルゴリズムの一部として命令形で書かれた要件(例:「先頭の空白文字をすべて取り除く」や「偽を返してこれらの手順を中止する」など)は、 アルゴリズムの導入に使われているキーワード("must", "should", "may" など)の意味で解釈されます。

アルゴリズムや特定の手順として表現された適合性要件は、最終的な結果が同等であれば、どのような方法で実装してもかまいません。 特に、この仕様で定義されているアルゴリズムは理解しやすいことを目的としており、性能を重視していません。 実装者は最適化することが推奨されます。

索引

この仕様で定義されている用語

参照によって定義される用語

参考文献

規範参考文献

[DeRemer1969]
Practical Translators for LR(k) Languages. 1969年10月24日. URL: http://publications.csail.mit.edu/lcs/pubs/pdf/MIT-LCS-TR-065.pdf
[ECMASCRIPT]
ECMAScript 言語仕様. URL: https://tc39.es/ecma262/multipage/
[IEEE-754]
IEEE 浮動小数点演算の標準. 2008年8月29日. URL: http://ieeexplore.ieee.org/servlet/opac?punumber=4610933
[Muller2005]
ulp(x) の定義について. 2005年2月. URL: https://inria.hal.science/inria-00070503
[RFC2119]
S. Bradner. RFC における要件レベルを示すキーワード. 1997年3月. ベスト現行標準. URL: https://datatracker.ietf.org/doc/html/rfc2119
[UAX14]
Robin Leroy. Unicode 行分割アルゴリズム。2025年9月5日。Unicode 標準付属書 #14。URL: https://www.unicode.org/reports/tr14/tr14-55.html
[UAX31]
Mark Davis; Robin Leroy. Unicode 識別子と構文。2025年8月20日。Unicode 標準付属書 #31。URL: https://www.unicode.org/reports/tr31/tr31-43.html
[UnicodeVersion14]
The Unicode Standard, Version 14.0.0. URL: http://www.unicode.org/versions/Unicode14.0.0/
[VanWyk2007]
Eric R. Van Wyk; August C. Schwerdfeger. 拡張言語のパースのためのコンテキスト認識スキャン. 2007年. URL: https://dl.acm.org/doi/10.1145/1289971.1289983
[VulkanMemoryModel]
Jeff Bolz; 他. Vulkan メモリモデル. URL: https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#memory-model
[WebGPU]
Kai Ninomiya; Brandon Jones; Myles C. Maxfield. WebGPU. 作業草案. URL: https://w3.org/TR/webgpu

参考情報

[CHARMOD-NORM]
Addison Phillips; 他. World Wide Web の文字モデル: 文字列照合. 2021年8月11日. 注記. URL: https://www.w3.org/TR/charmod-norm/
[CSS-TABLES-3]
François Remy; Greg Whitworth; David Baron. CSS テーブルモジュール レベル3. 2019年7月27日. 作業草案. URL: https://www.w3.org/TR/css-tables-3/
[IANA-MEDIA-TYPES]
メディアタイプ. URL: https://www.iana.org/assignments/media-types/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra 現行標準. 現行標準. URL: https://infra.spec.whatwg.org/
[Jeannerod2013]
Claude-Pierre Jeannerod; Nicolas Louvet; Jean-Michel Muller. 2x2 行列式を高精度で計算するための Kahan のアルゴリズムのさらなる解析. URL: https://www.ams.org/journals/mcom/2013-82-284/S0025-5718-2013-02679-8/S0025-5718-2013-02679-8.pdf
[WASM-CORE-2]
Andreas Rossberg. WebAssembly コア仕様. 2025年6月16日. 候補勧告草案. URL: https://www.w3.org/TR/wasm-core-2/