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

WebGPU で GPU の能力を引き出して、機械学習のパフォーマンスとグラフィックのレンダリングを高速化する方法を学びます。

新しい WebGPU API を使用すると、グラフィックと機械学習のワークロードでパフォーマンスが大幅に向上します。この記事では、現在の WebGL ソリューションに対する WebGPU の改良点と、今後の展開をいち早くご紹介します。その前に、WebGPU が開発された理由を説明しておきましょう。

WebGPU のコンテキスト

WebGL は 2011 年にリリースされました。ウェブ アプリケーションで GPU を活用できるようにすることで、Google Earth、インタラクティブなミュージック ビデオ、3D の不動産チュートリアルなど、ウェブで優れたエクスペリエンスが実現します。WebGL は、1992 年に初めて開発された OpenGL API ファミリーのベースになっています。かなり前のことだね!当時、GPU ハードウェアは大幅に進化してきたことがご想像のとおりです。

この進化に後れを取らないよう、最新の GPU ハードウェアとより効率的にやり取りするための新しい API が開発されました。Direct3D 12MetalVulkan などの API。これらの新しい API は、ML の爆発的な進歩やレンダリング アルゴリズムの進歩など、GPU プログラミングの新しく要求の厳しいユースケースをサポートしてきました。WebGPU は、この新しいクラスの最新 API の進歩をウェブにもたらす WebGL の後継です。

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 推論の高速化

また、近年 GPU の主流となっている機械学習の高速化にも役立っています。

クリエイティブ デベロッパーは長い間、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 ファーストの設計

このようなユースケースを可能にする機能は、プラットフォーム固有のデスクトップ / モバイル デベロッパーに以前から利用可能でしたが、ウェブ プラットフォームの自然な部分のように感じられる方法で公開することが、Google の課題でした。

WebGPU は、10 年以上にわたるデベロッパーが WebGL で驚異的な作業をこなしてきた経験から開発されました。私たちは、お客様が直面した問題、直面したボトルネック、開発者が提起した問題を取り込んで、すべてのフィードバックをこの新しい API に注ぎ込むことができました。

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

WebGL アプリケーションのデバッグは面倒であるというご意見をいただいていたため、WebGPU には、パフォーマンスを低下させることのない、より柔軟なエラー処理メカニズムが搭載されています。また、API から返されるメッセージはすべてわかりやすく、実行に移せるものになるように心がけています。

また、JavaScript 呼び出しが多すぎるとオーバーヘッドが複雑な WebGL アプリケーションのボトルネックになることも頻繁に確認されています。その結果、WebGPU API の処理量が減るため、より少ない関数呼び出しで多くのことを実行できます。重い検証を前もって実行することに重点を置き、重要な描画ループを可能な限り無駄にしないようにします。また、多数の描画コマンドを事前に記録して 1 回の呼び出しで再生できる、レンダリング バンドルなどの新しい API も用意されています。

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

アート ギャラリー

一方、WebGPU レンダラでは、スナップショット レンダリングと呼ばれる機能を利用できます。WebGPU のレンダリング バンドル上に構築されたこの機能により、同じシーンを 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 の採用が進んでいます。WebGPU のサポートは、現在も進行中であるか、多くの一般的な JavaScript WebGL ライブラリですでに完了しています。場合によっては、1 つのフラグを変更するだけで WebGPU のメリットを活用できる場合があります。

Babylon.js、Construct 3、Google Earth、Google Meet、PlayCanvas、Sketchfab、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 開発を初めて行う場合でも試すことができます。

API を体験するには、WebGPU のサンプルもご利用ください。従来の「ハロー トライアングル」から、より完全なレンダリングやコンピューティング パイプラインまで、さまざまな手法が示されています。最後に、その他のリソースをご確認ください。