OpenSiv3D for Web での WebGPU の有効化と WebGL/WebGPU バックエンドの比較

## 背景

世間では WebGPU といえば [wgpu](https://wgpu.rs) というところでしょう。しかし、emscripten にも WebGPU を扱うためのバインディングが用意されており、WebGPU を使った Web アプリを開発することができます。

ブラウザ側でも WebGPU 対応はもう間も無く[^caniuse]といったところまできており、Chrome v102 からフラグなしで利用可能になる予定です[^chrome-webgpu]。

[^chrome-webgpu]: <https://www.chromestatus.com/feature/6213121689518080>
[^caniuse]: <https://caniuse.com/webgpu>

OpenSiv3D for Web では、今年7月から WebGPU バックエンドの実装の優先度を高め、その実装を進めてきました。OpenSiv3D for Web の WebGPU バックエンドは v0.6.3 から、実験的な機能として利用可能になります。

OpenSiv3D for Web v0.6.3 の WebGPU バックエンドのサンプルは [このページ](https://siv3d-v6-apps.kamenokosoft.com/tests.html) からアクセスできます。

## この記事で得られる知見

* OpenSiv3D for Web v0.6.3 で WebGPU バックエンドを有効にする方法
* OpenSiv3D for Web v0.6.3 での WebGL/WebGPU バックエンドの性能の考察 (ただし、動作検証環境は1つだけのため参考程度に)

## WebGPU バックエンドの制限事項

* **Chrome Canary (Windows, macOS)** で **enable-unsafe-webgpu** のフラグを有効にしたうえで動作します
* VideoReader, WebCam, ScreenCapture, Texture::readRT は未実装のため利用できません
* レンダーターゲットの切り替え時に、viewport の範囲がおかしくなる現象が発生します

![enable-webgpu](https://img-blog.csdnimg.cn/20190615185902953.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NheGlleW91,size_16,color_FFFFFF,t_70)

# OpenSiv3D for Web v0.6.3 で WebGPU アプリを作成する

## OpenSiv3D for Web v0.6.3 のインストール

通常版の OpenSiv3D for Web に WebGL2 バックエンド、WebGPU バックエンドの両方が含まれています。OpenSiv3D for Web のインストールは [OpenSiv3D for Web プロジェクトサイト](https://siv3d.kamenokosoft.com/ja/building/overview) を参照してください

## WebGPU バックエンドを有効にする

次の一行をグローバルスコープに追加します。

```cpp
SIV3D_SET(EngineOption::Renderer::WebGPU)
```

例えば、[OpenSiv3D for Web プロジェクトサイトのトップページに掲載しているコードサンプル](https://siv3d.kamenokosoft.com/ja/index) では、次の通りに一行を追加します。

```cpp:Main.cpp
# include <Siv3D.hpp>

SIV3D_SET(EngineOption::Renderer::WebGPU)

void Main()
{
  // 背景を水色にする
  Scene::SetBackground(ColorF{ 0.8, 0.9, 1.0 });

  // 通常のフォントを作成
  const Font font{ 60 };
  
  // 絵文字用フォントを作成
  const Font emojiFont{ 60, Typeface::ColorEmoji };
  
  // `font` が絵文字用フォントも使えるようにする
  font.addFallback(emojiFont);

  // 画像ファイルからテクスチャを作成
  const Texture texture{ U"example/windmill.png" };

  // 絵文字からテクスチャを作成
  const Texture emoji{ U"🐈"_emoji };

  // 絵文字を描画する座標
  Vec2 emojiPos{ 300, 150 };

  // テキストを画面にデバッグ出力
  Print << U"Push [A] key";

  while (System::Update())
  {
    // テクスチャを描く
    texture.draw(200, 200);

    // テキストを画面の中心に描く
    font(U"Hello, Siv3D!🚀").drawAt(Scene::Center(), Palette::Black);

    // サイズをアニメーションさせて絵文字を描く
    emoji.resized(100 + Periodic::Sine0_1(1s) * 20).drawAt(emojiPos);

    // マウスカーソルに追随する半透明な円を描く
    Circle{ Cursor::Pos(), 40 }.draw(ColorF{ 1, 0, 0, 0.5 });

    // もし [A] キーが押されたら
    if (KeyA.down())
    {
      // 選択肢からランダムに選ばれたメッセージをデバッグ表示
      Print << Sample({ U"Hello!", U"こんにちは", U"你好", U"안녕하세요?" });
    }

    // もし [Button] が押されたら
    if (SimpleGUI::Button(U"Button", Vec2{ 640, 40 }))
    {
      // 画面内のランダムな場所に座標を移動
      emojiPos = RandomVec2(Scene::Rect());
    }
  }
}
```

# WebGPU バックエンドと WebGL バックエンドの性能比較

OpenSiv3D for Web v0.6.3 のサンプルを [このページ](https://siv3d-v6-apps.kamenokosoft.com/tests.html) において、 WebGL2 バックエンド、WebGPU バックエンド別に掲載してあります。

## 手元の環境での性能比較のまとめ

以下は手元の環境 (MacBook Air, 2015) での動作比較です。

* WebGL/WebGPU バックエンドの差を感じられるサンプルはあまりありませんでした
* GPU 負荷の特に高いサンプルでは、フレームレートの向上がみられます
  * SivSky を使うサンプルでは、WebGL バックエンドでは 40fps 程度しかでなかったのが、WebGPU バックエンドでは 60fps までフレームレートが改善しました
* CPU と GPU のデータのやり取りが多いサンプルでも、WebGPU バックエンドで負荷が小さくなるわけではありませんでした
  * データコピーに `GPUQueue.writeBuffer` を使っているため？
  * これは、将来のリリースで改善される可能性があります。 

参考程度に、EmpoweredAudio、GeoJson、Test3DSky のパフォーマンスインスペクタのスクリーンショットと簡単な考察を以下に掲載します。

### EmpoweredAudio

ほとんど差を感じられませんでした。

#### [WebGL バックエンド](https://siv3d-v6-apps.kamenokosoft.com/EmpoweredAudio/EmpoweredAudio.html)

![スクリーンショット 2021-12-01 20.58.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158514/b56cfbb9-5f86-3e96-c959-71d8eef78734.png)

#### [WebGPU バックエンド](https://siv3d-v6-apps.kamenokosoft.com/WebGPU/EmpoweredAudio/EmpoweredAudio.html)

![スクリーンショット 2021-12-01 21.00.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158514/cf2521dd-2b7c-85b1-411d-830abab56bbf.png)

### GeoJson

若干 WebGPU バックエンドの方がもたついているように感じられました。

#### [WebGL バックエンド](https://siv3d-v6-apps.kamenokosoft.com/GeoJson/GeoJson.html)

![スクリーンショット 2021-12-01 21.31.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158514/cacd7299-36de-a854-6bc0-6121b4f86668.png)

#### [WebGPU バックエンド](https://siv3d-v6-apps.kamenokosoft.com/WebGPU/GeoJson/GeoJson.html)

![スクリーンショット 2021-12-01 21.32.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158514/0829c236-b97c-c475-107c-5f9b02a7cbf2.png)

### Test3DSky

WebGPU バックエンドの方で CPU 負荷が上昇していますが、安定してフレームレートを保てています。

#### [WebGL バックエンド](https://siv3d-v6-apps.kamenokosoft.com/Test3DSky/Test3DSky.html)

![スクリーンショット 2021-12-01 21.18.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158514/74639067-f665-70ca-9b27-9f0f958940ed.png)

![スクリーンショット 2021-12-01 21.15.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158514/bb281215-1f58-3067-ccbf-980f7b1f4b9e.png)

#### [WebGPU バックエンド](https://siv3d-v6-apps.kamenokosoft.com/WebGPU/Test3DSky/Test3DSky.html)

![スクリーンショット 2021-12-01 21.18.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158514/fcc6be01-8670-0d86-fe59-c38a7e713970.png)

![スクリーンショット 2021-12-01 21.16.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158514/f0deb24b-aca4-a675-e78a-9346ddca7e06.png)