
はじめに
WebGPUは現在W3Cで仕様策定中である、Vulkan、Metal、Direct3D 12にある概念をベースとした汎用性の「モダンな3D画像処理と計算機能」APIです。
Apple、Mozilla、Microsoft、Googleの協力の元で開発されているということで非常に期待が持てるものとなっています。
WebGL2.0がsafari 15からサポートされ出したというタイミングではありますが、さらにその先を見据えてという事で大雑把にですが内容を見ていきたいと思います。
仕様
WebGPU
一連の流れについてはIntroductionに書かれています。
雑にいうと使用するデータ、各シェーダーステージにバンドルする内容、各パイプラインの内容を設定した上でエンコードを行っていくという「モダン」な作りとなっています。
WebGLと比較した場合での大きな優位点としてはレンダリング以外の専用のcompute shader stageを扱うことができるというものがあり、GPGPUを行う際などに楽に実装ができるようになります。
WebGPU Shading Language
シェーダー言語はWGSL(WebGPU Shading Language)です。
プレーン型としてはbool、数値、ベクトル、行列があります。
また扱える数値としては32-bitのuint(u32)、int(i32)、float(f32)となっています。
エントリポイントに入ってくる組み込み変数や、一般的なシェーダーにあるような組み込み関数も用意されています。
バンドルされた内容やアウトプット、インプットなどをまとめて表すには構造体を使用します。
環境構築
最新の状況に関してはChrome Canaryでのみ安定しているようです。
インストール後にchrome://flags/#enable-unsafe-webで対象の設定項目を開き、WebGPUの有効化を行います。
(有効化したまま信頼できないサイトへのアクセスを行わないように注意してください。自己責任でお願いします。)
Typescriptの型定義ファイルについてはgpuweb/typesにあります。
またWebpack5のAsset Modulesでシェーダーを別ファイルから読み取るような作りとしておくと便利かなと思います。
動く内容を確認するというところではWebGPU Samplesのサンプル群が参考になりました。
WebGPUの仕様更新に合わせてサンプルも随時更新されているようです。
W3Cのドキュメントのみでわかりづらいところなど、こちらのソースを見ながらだと理解が早いかと思われます。
試す
実際に触ってみるというところでfluidにある流体の実装を参考として、GPGPUの扱いをテクスチャによるものからcompute shaderに変更する形で対応してみました。
流体の計算を主として進めるため描画は参考まで凝ったものとせず、Pointで描画する形を取っています。
MacBook Pro (13-inch, 2019)でパーティクル数を80万としてもほぼほぼフレーム落ちせずに動いています。
これより対応してみた上で参考となった情報などを記載していきます。
入力と出力の入れ替え
フレームの更新毎や圧力を計算するループの部分でバインドするバッファの入力と出力を逆としたい部分についてはこちらを参考にしました。
GPUBindGroupを配列で用意し、更新やループのカウント毎でGPUComputePassEncoderにセットするGPUBindGroupを差し替えるという内容となっています。
シェーダー側でのデータの扱い
Typescript側でFloat32Arrayから作成したGPUBufferをシェーダー側でvec4の配列として利用したいケースでは、以下のように構造体を用意して型として設定することになります。
[[block]] struct Float32Vec4Array {
data: [[stride(16)]] array<vec4<f32>>;
};
[[binding(7), group(0)]] var<storage, write> resultVelocity: Float32Vec4Array;
storageに対して直接arrayを指定しようとすると
「variables declared in the storage class must be of a structure type」
というようなParser errorのメッセージが出てしまいます。
またアクセスのためのindexについてはパーティクルとグリッドセルを扱うかでGPUCommandEncoderのdispatchの引数を変え、組み込み変数のglobal_invocation_idで対象のindexを取得する形になります。
リソース競合の対応
リソース競合の回避にはAtomic Typesが使用できます。
パーティクルからグリッド上の流速を求める際などに利用しました。
Atomic Typesは現状u32かi32としてでしか扱えないといった仕様のため扱いには多少注意が必要となります。
数値制限など
各数値制限についてはこちらに記述があります。
シェーダーステージで扱えるstorageの数など設計前に把握していると良いかと思います。
データの中身の確認
開発中にGPUBufferの中身を覗きたい場合ですが、GPUBufferDescriptorのBuffer Usageの設定が必要となっています。
具体的にはGPUBufferUsage.MAP_READを指定する必要がありますが、こちらの読み取るGPUBufferをコピーしてという内容がとても参考となりました。
さいごに
今回はCompute部分を中心に触ってみましたが、GPGPUをブラウザで手軽に試せるというのは大変魅力的に感じました。
現在が仕様策定中なため今後仕様の変更が発生する可能性は十分にありますが、将来のウェブ標準というところでもし興味があれば触ってみるのはいかがでしょうか?
参考
- WebGPU W3C Working Draft
- WebGPU
- WebGPU Shading Language
- Get started with GPU Compute on the web
- WebGPU Samples
- fluid
- ウィキペディア WebGPU
- WebGL 2.0