WebGPU: ブラウザで最新の GPU へのアクセスが可能に

WebGPU が GPU の能力を解き放ち、機械学習のパフォーマンスを向上させ、グラフィック レンダリングを改善する方法について学びます。

新しい WebGPU API により、グラフィック ワークロードと ML ワークロードのパフォーマンスが大幅に向上します。この記事では、WebGPU が現在の WebGL のソリューションからどのように改善され、今後の開発がどのように行われているのかを紹介します。まず、WebGPU が開発された理由について説明します。

WebGPU のコンテキスト

WebGL は 2011 年に Chrome に導入されました。WebGL では、ウェブ アプリケーションで GPU を利用できるため、Google Earth やインタラクティブなミュージック ビデオ、3D 不動産ウォークスルーなど、ウェブ上で驚きの体験を実現できます。WebGL は、1992 年に初めて開発された OpenGL ファミリーの API をベースとしています。かなり前ですね。それ以降、GPU ハードウェアは大幅に進化しています。

この進化に対応するため、最新の GPU ハードウェアとより効率的にやり取りする新しい種類の API が開発されました。Direct3D 12MetalVulkan などの API です。これらの新しい API は、機械学習の急増やレンダリング アルゴリズムの進歩など、GPU プログラミングの新しい要求の厳しいユースケースをサポートしています。WebGPU は WebGL の後継であり、この新しいクラスの最新 API の先進的な機能をウェブに提供します。

WebGPU により、ブラウザで GPU プログラミングの可能性が大きく広がります。最新の GPU ハードウェアの仕組みをより適切に反映し、将来の高度な GPU 機能の基盤を築きます。この API は 2017 年から W3C の「GPU for the Web」グループで開発されており、Apple、Google、Mozilla、Microsoft、Intel などの多くの企業が協力して開発しています。そして 6 年にわたる取り組みを経て、ついにウェブ プラットフォームに最大級の機能が加わったことを発表いたします。

WebGPU は現在、ChromeOS、macOS、Windows 版 Chrome 113 で利用できます。他のプラットフォームにも近日中に対応する予定です。これを実現するために協力してくれた他の Chromium コントリビューター、特に Intel に心から感謝いたします。

では、WebGPU によって可能になる魅力的なユースケースをいくつか見てみましょう。

レンダリング用の新しい GPU ワークロードを活用する

コンピューティング シェーダーなどの WebGPU 機能により、新しいクラスのアルゴリズムを GPU に移植できます。たとえば、シーンに動的で詳細なディテールを追加したり、物理現象をシミュレートしたりできるアルゴリズムなどです。これまで JavaScript でしか実行できなかったワークロードも、GPU に移行できるようになりました。

次の動画は、これらのメタボールのサーフェスを三角形分割するために使用されるマーチング キューブ アルゴリズムを示しています。動画の最初の 20 秒間で、JavaScript で実行されているアルゴリズムは、8 FPS でしか実行されていないページに対応するのに苦労するため、アニメーションが不自然になります。JavaScript でパフォーマンスを維持するには、詳細レベルを大幅に下げる必要があります。

同じアルゴリズムをコンピューティング シェーダーに移行すると、動画の 20 秒目以降に示すように、パフォーマンスが大幅に向上します。ページがスムーズな 60 FPS で表示されるようになったことで、パフォーマンスは劇的に向上しました。他の効果にはまだパフォーマンスの余地がたくさんあります。また、ページのメインの JavaScript ループが他のタスクのために完全に解放されるため、ページの操作が常に応答するようになります。

メタボールのデモ

また、WebGPU では、これまでは実用的ではなかった複雑な視覚効果も実現できます。次の例は、一般的な Babylon.js ライブラリで作成されています。海面はすべて GPU でシミュレートされています。リアルなダイナミクスは、多くの独立した波を重ね合わせることで作成されます。ただし、各波を直接シミュレートすると費用がかかりすぎます。

海のデモ

そのため、このデモでは高速フーリエ変換と呼ばれる高度なアルゴリズムを使用しています。すべての波を複雑な位置データとして表すのではなく、計算を実行する際にはスペクトル データを使用するため、より効率的です。次に、各フレームでフーリエ変換を使用して、スペクトル データから波の高さを表す位置データを変換します。

ML 推論の高速化

WebGPU は、近年 GPU の主要な用途となっている ML の高速化にも役立ちます。

長い間、クリエイティブ デベロッパーは WebGL のレンダリング API を再利用して、ML 計算などのレンダリング以外の処理を実行してきました。ただし、この方法では、計算を開始する方法として三角形のピクセルを描画し、より汎用的なメモリアクセスではなく、テクスチャ内のテンソルデータを慎重にパックと解凍する必要があります。

WebGL での単一の ML 演算子の実行における非効率性(冗長なメモリ読み込み、冗長な計算、スレッドあたりの書き込み値が少ないなど)を示す図。
WebGL による単一の ML 演算子の実行。

このように WebGL を使用すると、デベロッパーは描画専用に設計された API の要件にコードを無理やり合わせる必要があります。計算間での共有メモリ アクセスなどの基本機能が不足していることも相まって、作業が重複し、最適なパフォーマンスが得られません。

コンピューティング シェーダーは WebGPU の主な新機能であり、これらの問題を解消します。コンピューティング シェーダーは、レンダリング オペレーションの厳格な構造に制約されることなく、GPU の超並列性を利用できる、より柔軟なプログラミング モデルを提供します。

共有メモリ読み込み、共有コンピューティング、メモリへの柔軟な書き込みなど、WebGPU コンピューティング シェーダーのさまざまな効率向上。
WebGPU コンピューティング シェーダーの効率性。

コンピューティング シェーダーを使用すると、シェーダー処理のグループ内でデータと計算結果を共有できるため、効率性が向上します。これにより、同じ目的で WebGL を使用しようとしたこれまでの試みよりも大幅なパフォーマンス向上が期待できます。

これにより得られる効率性の向上の一例として、TensorFlow.js の画像拡散モデルの最初のポートは、WebGL から WebGPU に移行したときに、さまざまなハードウェアでパフォーマンスが 3 倍向上しています。テストした一部のハードウェアでは、画像が 10 秒未満でレンダリングされました。この機能はまだ初期の段階から移行していたため、WebGPU と TensorFlow.js の両方でさらなる改善が可能なものと考えています。2023 年のウェブ ML の新機能をGoogle I/O セッション。

ただし、WebGPU の目的は、GPU 機能をウェブに導入することだけではありません。

JavaScript 向けに設計

このようなユースケースを実現する機能は、プラットフォーム固有の PC デベロッパーとモバイル デベロッパーが長い間利用してきました。ウェブ プラットフォームの自然な一部のようにこれらの機能を公開することが、Google の課題でした。

WebGPU は、10 年以上にわたり WebGL で優れた成果をあげているデベロッパーたちの知見を活用して開発されました。ユーザーから寄せられた問題、ボトルネック、問題をすべてこの新しい API にフィードバックしました。

WebGL のグローバルな状態モデルにより、堅牢でコンポーズ可能なライブラリやアプリケーションの作成が困難かつ脆弱であることが判明しました。そのため WebGPU では、開発者が GPU コマンドを送信する際に追跡する必要がある状態の量を大幅に削減できます。

WebGL アプリケーションのデバッグが面倒だという声をよく聞きます。WebGPU には、パフォーマンスを低下させない、より柔軟なエラー処理メカニズムが含まれています。また、API から返されるすべてのメッセージがわかりやすく、実用的な内容になるよう、細心の注意を払っています。

また、JavaScript 呼び出しが多すぎることによるオーバーヘッドが、複雑な WebGL アプリケーションのボトルネックになることもよく見られました。その結果、WebGPU API ではチャットが少なくなり、より少ない関数呼び出しでより多くの処理を実行できます。前もって重量級の検証を行うことに重点を置き、クリティカルな描画ループをできるだけ無駄をなくします。また、レンダリング バンドルなどの新しい API も提供されています。これにより、大量の描画コマンドを事前に記録し、1 回の呼び出しで再生できます。

レンダリング バンドルなどの機能がもたらす劇的な違いを示すために、Babylon.js の別のデモを紹介します。この WebGL 2 レンダラは、すべての JavaScript 呼び出しを実行して、このアートギャラリーのシーンを 1 秒あたり約 500 回レンダリングできます。かなり良いです。

アート ギャラリー

ただし、WebGPU レンダラでは、スナップショット レンダリングと呼ばれる機能が有効になっています。WebGPUs レンダリング バンドル上に構築されたこの機能により、同じシーンの送信速度が 10 倍以上になります。これによりオーバーヘッドが大幅に削減されるため、WebGPU はより複雑なシーンをレンダリングすると同時に、アプリケーションで JavaScript を使用してより多くの処理を並行して実行できます。

最新のグラフィック API は複雑で、シンプルさを犠牲にして極端な最適化の機会を追求しているという評判があります。一方、WebGPU はクロスプラットフォームの互換性に重点を置いており、リソースの同期など、従来は難しかったトピックをほとんどの場合自動的に処理します。

これには、WebGPU が容易に習得して使用できるというメリットがあります。画像や動画の読み込みなどはウェブ プラットフォームの既存の機能に依存し、非同期処理には Promise などのよく知られた JavaScript パターンを利用しています。これにより、必要なボイラプレートコードの量を最小限に抑えることができます。50 行のコードで最初の三角形を画面に表示できます。

<canvas id="canvas" width="512" height="512"></canvas>
<script type="module">
  const adapter = await navigator.gpu.requestAdapter();
  const device = await adapter.requestDevice();

  const context = canvas.getContext("webgpu");
  const format = navigator.gpu.getPreferredCanvasFormat();
  context.configure({ device, format });

  const code = `
    @vertex fn vertexMain(@builtin(vertex_index) i : u32) ->
      @builtin(position) vec4f {
       const pos = array(vec2f(0, 1), vec2f(-1, -1), vec2f(1, -1));
       return vec4f(pos[i], 0, 1);
    }
    @fragment fn fragmentMain() -> @location(0) vec4f {
      return vec4f(1, 0, 0, 1);
    }`;
  const shaderModule = device.createShaderModule({ code });
  const pipeline = device.createRenderPipeline({
    layout: "auto",
    vertex: {
      module: shaderModule,
      entryPoint: "vertexMain",
    },
    fragment: {
      module: shaderModule,
      entryPoint: "fragmentMain",
      targets: [{ format }],
    },
  });
  const commandEncoder = device.createCommandEncoder();
  const colorAttachments = [
    {
      view: context.getCurrentTexture().createView(),
      loadOp: "clear",
      storeOp: "store",
    },
  ];
  const passEncoder = commandEncoder.beginRenderPass({ colorAttachments });
  passEncoder.setPipeline(pipeline);
  passEncoder.draw(3);
  passEncoder.end();
  device.queue.submit([commandEncoder.finish()]);
</script>

まとめ

WebGPU がウェブ プラットフォームにもたらす新しい可能性に期待しています。WebGPU の新しいユースケースがどのように広がっていくのか、楽しみです。

WebGL を中心に、ライブラリとフレームワークの活気あるエコシステムが構築されています。このエコシステムは、WebGPU を積極的に採用しています。多くの一般的な JavaScript WebGL ライブラリで、WebGPU のサポートが進行中または完了しています。場合によっては、1 つのフラグを変更するだけで、WebGPU のメリットを活用できることもあります。

Babylon.js、Construct 3、Google Earth、Google Meet、PlayCanvas、Scottfab、Three.JS、TensorFlow.js、Unity。
WebGPU ポートが完了または進行中のフレームワーク、アプリケーション、ライブラリ。

そして、この Chrome 113 の最初のリリースは始まりにすぎません。初回リリースは Windows、ChromeOS、MacOS ですが、将来的には Android や Linux など、残りのプラットフォームでも WebGPU を提供する予定です。

WebGPU のリリースに向けて取り組んでいるのは Chrome チームだけではありません。Firefox と WebKit でも実装が進行中です。

また、ハードウェアで利用可能になったときに公開できる新機能が W3C ですでに設計されています。たとえば、Chrome では、機械学習のパフォーマンスをさらに向上させるため、まもなくシェーダーでの 16 ビット浮動小数点数をサポートし、DP4a クラス命令を有効にすることを計画しています。

WebGPU は、投資すれば驚異的なパフォーマンスを発揮する包括的な API です。今回はそのメリットの概要しか説明できませんでしたが、WebGPU を初めて使用する場合は、入門編の Codelab「初めての WebGPU アプリ」をご覧ください。この Codelab では、名作コンウェイのライフゲームの GPU 版を作成します。この Codelab では、GPU 開発を初めて行う場合でも試すことができる、手順を順を追って説明します。

WebGPU サンプルも、API を試すには適しています。従来の「Hello Triangle」から、より完全なレンダリング パイプラインとコンピューティング パイプラインまで、さまざまなテクニックが示されています。その他のリソースもご覧ください。