この記事について
前回の記事は、UnityやUnreal EngineがThree.jsとは違うアプローチで、エンジン本体をWebAssemblyに変換してブラウザに持ち込んでいることを説明しました。今回はシリーズ最終回として、「NVIDIAやAMD、Intelなど、GPUの種類によって挙動が変わることがあるのはなぜか」を掘り下げます。
結論から言うと、GPUベンダーやドライバによる相性問題は実際に存在し、ブラウザとGPUの間にいくつもの"翻訳層"が挟まっていることがその一因です。
WebGLは実は「そのままGPUに命令が渡っている」わけではない
多くの人は、「WebGLの命令 → そのままGPUで実行される」とイメージするかもしれません。しかし実際には、ChromeやFirefoxなどのブラウザは、WebGLの命令をいったんANGLEというGoogle製の翻訳レイヤーに通しています。
ANGLEは、WebGLのようなOpenGLスタイルのAPI呼び出しを受け取り、それを実行環境に応じてVulkan、DirectX、Metalといった、各OS・各GPUベンダーが提供するネイティブなグラフィックスAPIのコマンドに変換する役割を担っています。
実際の経路を図にすると、こうなります。
この「翻訳」の段階こそが、GPUベンダーやドライババージョンによる挙動差が生まれるポイントです。同じWebGLコードを書いても、実行環境によって最終的に呼ばれるネイティブAPIが変わり、そのAPIとGPUドライバの組み合わせ次第で結果が変わってきます。
実際に起きている相性問題の具体例
1. ブラウザの「GPUブロックリスト」
ブラウザは、既知の不具合があるGPU・ドライバの組み合わせをあらかじめ「ブロックリスト」として持っており、該当する環境ではハードウェアアクセラレーションを無効化し、ソフトウェアレンダリング(CPUで代用描画する、非常に遅いモード)に自動的にフォールバックすることがあります。
実際の障害報告では、Chromeで一部のIntel統合GPU搭載のWindows機において、GPUプロセスが大量のメモリを消費しWebGLのコンテキストが失われるというバグが確認されており、これはANGLEバックエンドの内部に絞り込まれた問題だったと報告されています。同じ報告の中では、あるマシンに搭載されていたNVIDIA GeForce RTX 2060という比較的新しいGPUでさえ、ブロックリストに入っていたケースもあったとされています。
つまり「新しくて高性能なGPUだから安心」とは必ずしも言えず、特定のドライババージョンとブラウザのバグの組み合わせで問題が起こることがあります。
2. ドライババージョンごとの不具合
NVIDIAやAMDのGPUドライバも、バージョンによって特定の不具合を抱えていることがあります。3DCG制作ソフトの技術サポート文書では、NVIDIAドライバのあるバージョンではレイトレーシングに関する表示の乱れが、また別のバージョンではテクスチャの破損やクラッシュが報告されており、AMDドライバでも特定のバージョン範囲でテクスチャのグリッチや安定性の問題が確認されているとされています。これはネイティブアプリケーションの例ですが、WebGL/WebGPUも最終的には同じGPUドライバの上で動くため、同種の問題が起こり得ます。
3. 統合GPUと専用GPUの取り違え
ノートPCなどでよくあるのが、Intelの統合GPUとNVIDIA/AMDの専用(discrete)GPUの両方を搭載した「ハイブリッド構成」での問題です。この場合、ブラウザが意図しない方のGPU(たとえば非力な統合GPU側)を選んでしまうことがあり、chrome://gpuという診断ページでGL_RENDERERの項目を確認し、想定と違うGPUが使われていないかチェックする必要があるとされています。
4. 圧縮テクスチャフォーマットの対応差
第2回で触れたBasis Universal/KTX2のような圧縮テクスチャフォーマットについても、GPUやOSによって対応状況に差があります。Khronos Groupの開発者ガイドでは、開発者は圧縮フォーマットの対応状況の違いを踏まえて幅広いプラットフォームでテストすべきだとされており、その中でも現代的なIntel GPU(Windows/Linux上)や、Apple M1以降のSoC(macOS上)が特に高い互換性を提供する組み合わせとして紹介されています。
WebGPUでも同様の構造がある
WebGL/ANGLEの話をしましたが、次世代の標準であるWebGPUでも、似た構造は変わりません。むしろ、より直接的にネイティブAPIを選択する形になっています。
Chromeの場合、WebGPUの実体はDawnというGoogle製の実装です。Chrome for Developersの公式解説によれば、DawnはC++で書かれており、実行環境に応じてDirect3D 12、Metal、Vulkanのいずれかにマッピングされるとされています。一方でFirefoxは、Rustで書かれたwgpuという別の実装を使っています。
つまりWebGPUの場合、「どのブラウザを使っているか」によっても、内部で呼ばれる実装(Dawn or wgpu)が変わり、さらに「どのOSで動いているか」によって、最終的に呼ばれるネイティブAPI(Vulkan/Metal/D3D12)が変わる、という2段階の分岐が発生します。それぞれの組み合わせごとにGPUドライバとの相性問題が起こり得るのは、WebGLの場合と同じ理屈です。
なぜこの複雑な仕組みが必要なのか
「最初からGPUに直接命令すればシンプルなのでは?」と思うかもしれませんが、これには理由があります。
- GPUベンダーごとにネイティブAPIが違う:Windowsでは主にDirectX、macOSではMetal、Linux/Androidでは主にVulkanが使われており、これらのAPIの仕様は互いに大きく異なります
- WebGL/WebGPUという「共通言語」を各OS・各ベンダー向けに翻訳する層(ANGLE、Dawn、wgpu)があることで、開発者は1つのコードでどの環境でも動くゲームを作れる
つまりANGLEやDawn/wgpuは、「ブラウザというプラットフォームの多様性を吸収するための緩衝材」のような役割を果たしています。ただし、その緩衝材自体にもバグや対応漏れがあるため、完全に相性問題がなくなるわけではない、というのがここまで見てきた内容です。
シリーズ全体のまとめ
4回にわたって、ブラウザの3D MMOがどう成り立っているかを見てきました。最後に全体を振り返ります。
- 第1回:ブラウザの3Dゲームは、基本的に手元のGPUがその場でリアルタイムに描画している(映像ストリーミングは例外的なケース)
- 第2回:3Dアセットはglft/Draco/Basis Universalなどで軽量化され、「全部先読み」または「オンデマンド」で届けられ、Cache API・IndexedDBなどに保存される
- 第3回:UnityやUnreal Engineは、Three.jsとは違い、エンジン本体をWebAssemblyにコンパイルしてブラウザに持ち込んでおり、JavaScriptのグルーコードがその起動とWebGL呼び出しを仲介している
- 第4回(本記事):WebGL/WebGPUの命令は、ANGLEやDawn/wgpuといった翻訳層を経由して各OS・各GPUベンダーのネイティブAPIに変換されるため、GPUの種類やドライババージョンによる相性問題が実際に発生し得る
ブラウザの3Dゲームは「JavaScriptだけで完結している」ように見えて、実際にはOS・GPUベンダー・ドライバ・ブラウザベンダーそれぞれの実装が幾重にも重なった、かなり複雑なスタックの上に成り立っています。この記事が、その裏側を覗く手がかりになれば幸いです。
参考資料
- Unity Discussions: Will WebGL end up running through ANGLE on all platforms
- GitHub Issue: Fix for RAM usage & WebGL Context Lost with Intel GPUs (OHIF/Viewers)
- superchargebrowser.com: WebGL Context Lost in Chrome? 5 TESTED Fixes
- Adobe: GPU drivers compatibility (Substance 3D Painter)
- Khronos Group: KTXDeveloperGuideWebGL.md
- Chrome for Developers: Capturing the WebGPU ecosystem
- webgpu.com: WebGPU Hits Critical Mass