1 はじめに
序文ブログ:
WebGPU——Draft 2023.7.17 はApple、Google、Mozilla のチームによって開始され、現在はドラフト段階にあり、W3C 推奨標準となることを目指しています。
WebGPU は、グラフィックス プロセッシング ユニット (GPU) でレンダリングや計算などの操作を実行するための API を提供します。
GPU は、リッチ レンダリングと並列コンピューティング アプリケーションをサポートします。WebGPU は、API を介して Web 用に GPU のハードウェア機能を使用します。WebGPU API は、ネイティブ GPU API への効率的なマッピングです。WebGPU は WebGL とは何の関係もなく、OpenGL ES (OpenGL for Embedded Systems) を明示的にアンカーしません。
ウェブGPU:
- 1) 物理 GPU ハードウェアを GPUAdapter として考えます。
- 2) GPUDevice を介して GPUAdapter を接続します。
- 3) GPUDevice の GPUQueue を使用して命令を実行します。
- 4) GPUDevice は、プロセッサ ユニットへの高速アクセスのために独自のメモリを備えている場合があります。
- 5) GPUBuffer と GPUTexture は、GPU メモリによってサポートされる物理リソースです。
- 6) GPUCommandBuffer と GPURenderBundle は、ユーザーが記録した命令のコンテナーです。
GPU は、GPUCommandBuffer でエンコードされた命令を実行し、パイプラインを通じてデータを供給します。- 6.1) GPUCommandBuffer: 固定機能ステージとプログラム可能なステージの混合で構成されます。
- プログラマブル ステージは、GPU ハードウェア上で実行するように設計された特定のプログラムであるシェーダーを実行します。シェーダー コードは、GPU ハードウェアの計算ユニット内で実行されます。
- 6.2) パイプライン: ほとんどのパイプライン状態は、GPURenderPipeline または GPUComputePipeline オブジェクトによって定義されます。
パイプライン オブジェクトに含まれない状態は、beginRenderPass() や setBlendConstant() などの命令エンコード フェーズを通じて設定されます。
- 6.1) GPUCommandBuffer: 固定機能ステージとプログラム可能なステージの混合で構成されます。
- 7) GPUShaderModule にはシェーダー コードが含まれています。
- 8) GPUSampler または GPUBindGroup。GPU が物理リソースを使用する方法を構成するために使用されます。
- 9) 将来的には、Web Workers を通じてマルチスレッドがサポートされる予定です。
2. 座標系
レンダリング操作では、次の座標系を使用できます。 [WebGPU の座標系は、グラフィックス パイプラインの DirectX 座標系と一致することに注意してください。】
-
1) 正規化されたデバイス座標 (NDC): 3 つの次元があります:
- − 1.0 ≤ x ≤ 1.0 -1.0\leq x \leq 1.0− 1.0≤バツ≤1.0。
- − 1.0 ≤ y ≤ 1.0 -1.0\leq y \leq 1.0− 1.0≤y≤1.0。
- 0.0 ≤ z ≤ 1.0 0.0\leq z \leq 1.00.0≤z≤1.0。
- 左下隅の座標は( − 1.0 , − 1.0 , z ) (-1.0, -1.0, z)です。( − 1.0 、− 1.0 、z )。
-
2) クリップ空間座標: 4 次元( x 、 y 、 z 、 w ) (x、y、z、w)( x ,よ、z 、w ):
- 2.1) クリップ スペース座標は次のとおりです。
- 頂点のクリップ位置 (つまり、頂点シェーダーの位置出力) として使用されます。
- クリップボリュームとして使用されます。
- 2.2) クリップ空間座標と正規化されたデバイス座標の関係は次のとおりです。
- 若点p = ( p . x , p . y , p . z , p . w ) p=(px,py,pz,pw)p=( p.x 、_ _p 。そして、p 。z 、p . w )がクリップ ボリューム内にある場合、その正規化されたデバイス座標は( p . x ÷ p . w 、 p . y ÷ p . w 、 p . z ÷ p . w ) (px\div pw, py \ div ) となります。 pw、pz \div pw)( p.x _ _÷p 。w、p 。と÷p 。w、p 。z÷p 。w )。
- 2.1) クリップ スペース座標は次のとおりです。
-
3) フレームバッファ座標: フレームバッファ内のピクセルをアドレス指定するために使用されます。
- 3.1) には 2 つの次元があります。
- 3.2) 各ピクセルはxxにありますx和yyy次元の単位は 1 です。
- 3.3) 左上隅の座標は( 0.0 , 0.0 ) (0.0, 0.0)です。( 0.0 ,0.0 )。
- 3.4)xx×は右に行くほど大きくなります。
- 3.5)yyyは横に伸びます。
-
4) ビューポート座標: フレームバッファ座標x、yx、y× 、y寸法に基づいて、深さzzが追加されますz。
- 通常0.0 ≤ z ≤ 1.0 0.0\leq z\leq 1.00.0≤z≤1.0ですが、minDepth と maxDepth は setViewport() を通じて変更できます。
-
5) フラグメント座標: vIewport 座標と一致します。
-
6) UV 座標: 2 次元のサンプル テクスチャに使用されます:
- 0 ≤ u ≤ 1.0 0\leq u\leq 1.00≤あなた≤1.0
- 0 ≤ v ≤ 1.0 0\leq v\leq 1.00≤v≤1.0
- ( 0.0 , 0.0 ) (0.0, 0.0)( 0.0 ,0.0 )は、テクスチャ メモリ アドレス シーケンスの最初のテクセルです。
- ( 1.0 , 1.0 ) (1.0, 1.0)( 1.0 、1.0 )は、テクスチャ メモリ アドレス シーケンスの最後のテクセルです。
-
7) ウィンドウ座標または現在の座標: 外部ディスプレイやその他のインターフェイスと対話するために使用されるフレームバッファー座標と一致します。
3. WebGPUプログラミングモデル
3.1 タイムライン
WebGPUの動作は「タイムライン」で表現されます。アルゴリズム内のすべての操作は、何らかのタイムラインで発生します。タイムラインは、操作の順序と、操作の対応する状態を明確に定義します。
WebGPU のタイムライン タイプは次のとおりです。 [不変の値はどのタイムラインにも使用できます]
- 1) コンテンツ タイムライン: Web スクリプトの実行に関連付けられます。このプロトコルを呼び出すすべてのメソッドが含まれます。
- 2) デバイス タイムライン: ユーザー エージェントによってリリースされた GPU デバイス操作に関連付けられます。含む:
- アダプター、デバイス、GPU リソース、および状態オブジェクトを作成します。ユーザー エージェントの観点から見ると、これらは古典的な同期操作です。
- 3) キュー タイムライン: GPU コンピューティング ユニット内の操作の実行に関連付けられます。実際に GPU で実行される描画、コピー、および計算ジョブが含まれます。
例:GPUDevice.createBuffer():
- 1) ユーザーは GPUBufferDescriptor を入力し、その GPUBuffer を作成します。これはコンテンツのタイムラインで発生します。
- 2) ユーザー エージェントは、デバイス タイムラインに基礎となるバッファを作成します。
3.2 メモリモデル
アプリケーションの初期化フェーズで GPUDevice が取得されると、WebGPU プラットフォームは次のレベルとして説明できます。
- 1) ユーザーエージェント: この契約を実施するために使用されます。
- 2) デバイスの基礎となるネイティブ API によって駆動されるオペレーティング システム。
- 3) 実際の CPU および GPU ハードウェア。
異なるレベルには異なるメモリタイプがあるため、ユーザーエージェントはこのプロトコルを実装するときに考慮する必要があります。
- 1) スクリプト所有のメモリ: たとえば、スクリプトによって作成された ArrayBuffer は、通常、GPU ドライバーからアクセスできません。
- 2) ユーザー agenet には、コンテンツの実行と GPU ドライバーとの通信を担当するさまざまなプロセスがある場合があります。この時点で、プロセス間共有メモリを使用してデータを転送します。
- 3) 特定の GPU には独自の高帯域幅メモリがあり、これらの統合 GPU は通常、システムとメモリを共有します。
GPU レンダリングまたはコンピューティングを効率的に行うために、ほとんどの物理リソースはメモリの形式で割り当てられます。ユーザーが GPU に新しいデータを提供する必要がある場合: [以下は最悪のケースです。実際の実装では、通常、プロセス境界を越えたり、ドライバー管理のメモリをユーザーの ArrayBuffer に直接公開したりする必要はなく、これにより、データのコピー。】
- 1) データは最初にプロセス境界を越え、GPU ドライバーと通信するユーザー エージェント部分に到達する可能性があります。
- 2) 次に、ドライバーから見えるようにする必要がある場合があり、ドライバーによって割り当てられたステージング メモリにコピーする必要がある場合もあります。
- 3) 最後に、データを GPU 専用メモリに転送する必要がある場合があり、内部レイアウトを GPU にとってより効率的なものに変換する可能性があります。
上記のデータ変換はすべて、WebGPU のユーザー エージェント Lai shixian d を同時に通過します。
4. 主要な内部オブジェクト
4.1 アダプター
アダプターは、WebGPU 実装を識別するために使用されます。
- ブラウザのコンピューティング機能またはレンダリング機能のインスタンスです。
- 例はブラウザの WebGPU にも実装されています。
アダプターは基礎となる実装を一意に識別しないため、requestAdapter()
複数回呼び出されるたびに異なるアダプター オブジェクトを返します。
各アダプター オブジェクトは、デバイスの作成にのみ使用できます。
- requestDevice() が成功を返した場合、アダプターは無効になります。
- さらに、アダプター オブジェクトはいつでも期限切れになる可能性があります。
これにより、アプリケーションは選択された最新のアダプター システム状態を使用してデバイスを作成することが保証され、より多くのシナリオで堅牢性も向上します。
アダプターは GPUAdapter として公開されます。
4.2 デバイス
デバイスはアダプターのロジックに対してインスタンス化され、それによって内部オブジェクトが作成されます。複数のエージェント (専属ワーカーなど) 間で共有できます。
device は、デバイスに基づいて作成されたすべての内部オブジェクトの外部所有者です。
- デバイスに障害が発生すると (紛失または破壊され)、デバイスに基づいて作成されたすべてのオブジェクト (createTexture() によって直接作成されたか、createView() の導入によって作成された) が暗黙的に使用できなくなります。
5. 主な機能
-
1) navigator.gpu: 利用可能な GPU オブジェクトを返します。
-
2) gpu.requestAdapter(): ユーザー エージェントからアダプターを要求します。
-
3)adapter.requestDevice():アダプターからデバイスを要求します。
-
4)adapter.requestAdapterInfo(); アダプターの GPUAdapterInfo を取得します。
-
5) device.destroy(): デバイスを破棄して、デバイス上での今後の操作を防止します。非同期操作は失敗します。同じデバイスが複数回破壊される可能性があります。
-
6) device.createBuffer(): GPUBuffer を作成します。GPUBuffer は、GPU コンピューティングに使用されるメモリを表します。データは線形レイアウトで保存されます。これは、割り当てられた各バイトが GPUBuffer の開始位置のオフセットに従ってアドレス指定できることを意味し、特定の操作に応じて配置制限があります。特定の GPUBuffers はマッピング可能であるため、ArrayBuffer を介してメモリ ブロックにアクセスできます。
-
7)GPUBuffer.destroy():GPUBufferを破棄します。
-
8) GPUBuffer.mapAsync(mode, offset, size): モードには読み取りまたは書き込みの 2 つのモードがあります。マッピング後は、ArrayBuffer を通じて GPUBuffer のコンテンツにアクセスできます。
-
9) GPUBuffer.getMappedRange(offset, size): GPUBuffer 内の指定されたマップ範囲の内容 (ArrayBuffer) を返します。
-
10) GPUBuffer.unmap(): コンテンツを GPU で再度使用できるようにマップを解除します。
-
11) device.createBindGroupLayout(): 単一のシェーダ リソースを GPUBindGroupLayout にバインドすることを示します。【wgslソースファイル数に応じて】
GPUShaderStageは以下の3種類があります。- VERTEX: 頂点シェーダーによってアクセス可能。
- FRAGMENT: フラグメント シェーダにアクセスできます。
- COMPUTE: 計算シェーダーによってアクセス可能。
-
12) device.createBindGroup(): GPUBindGroup を作成します。
-
13)device.createShaderModule():GPUShaderModuleを作成します。
-
14)device.createPipelineLayout():GPUPipelineLayout を作成します。
-
15) device.createComputePipeline(): 即時パイプライン作成メソッドを使用して、GPUComputePipeline を作成します。
-
16)device.createCommandEncoder():GPUCommandEncoder を作成します。
-
17) GPUCommandEncoder.beginComputePass(descriptor): 記述子によって記述されたコンピューティング パスのエンコードを開始します。
-
18)dispatchWorkgroups(workgroupCountX, workgroupCountY, workgroupCountZ): 作業を現在の GPUComputePipeline に分散して実行します。の:
- workgroupCountX:ディスパッチするワークグループのグリッドの X 次元。
- workgroupCountY:ディスパッチするワークグループのグリッドの Y 次元。
- workgroupCountZ:ディスパッチするワークグループのグリッドの Z 次元。
つまり、特定の GPUShaderModule によって定義されたエントリ ポイントに @workgroup_size(4, 4) があり、作業が を呼び出すことによって分散される場合
computePass.dispatchWorkgroups(8, 8)
、エントリ ポイントは合計 1024 回トリガーされます。- 4x4 ワークグループを X 軸に沿って 8 回、Y 軸に沿って 8 回分散します: 4 ∗ 4 ∗ 8 ∗ 8 = 1024 4*4*8*8=10244∗4∗8∗8=1024。
-
19) copyBufferToBuffer(source,sourceOffset,destination,destinationOffset,size):これは、GPUCommandEncoder のコマンドで、GPUBuffer サブ領域内のデータを別の GPUBuffer のサブ領域にコピーするために使用されます。
-
20) clearBuffer(buffer, offset, size): GPUBuffer のサブ領域データをクリアし、すべて 0 に設定します。
-
21) device.queue.writeBuffer(buffer,bufferOffset,data,dataOffset,size): GPUBufferの特定の領域に特定のデータを書き込みます。
-
22) device.queue.submit(commandBuffers): GPU のキュー内のコマンド バッファーの実行をスケジュールします。送信されたコマンド バッファは再度使用することはできません。
-
23) device.queue.onSubmittedWorkDone(): キューが現在送信されているすべての作業を完了すると、Promise を返します。