Continuation LabsのシニアソフトウェアエンジニアであるGabriel Cuvillier氏が、有名なDoom 3ゲームを、WebAssemblyを使ってブラウザに移植した。7週間に及ぶフルタイムの開発作業か明らかになったのは、ヘビーウェイトなデスクトアプリケーションやゲームをシームレスに実行する上で現在のWebAssemblyが持っている、潜在的パフォーマンスと不足している部分の両方だ。InfoQはCuvillier氏とのインタビューで、開発中に遭遇した技術的課題や、WebAssemblyを使ったデスクトップアプリケーションに移植を検討中の開発者が学ぶべき教訓について聞いた。
Doom 3は2004年、Microsoft Windows用としてリリースされた、ホラーを題材とした一人称型シューティングゲームだ。Doom 3では、2011年にGNU General Public License下でリリースされたid Tech 4ゲームエンジンを利用している。このゲームは商業面で大きな成功を収め、350万部以上が販売された。
InfoQ:WebAssemblyを使って、DOOM3をブラウザに移植しようと思った動機は何ですか?
2年前、WebAssembly MVPが主要なブラウザで一般的に利用可能になってから、テクノロジを中心としたハイプ・サイクル(hype cycle)が始まったと思います。賞賛の声が多く集まって、素敵なプレゼンテーションや講演がいたるところで行われるようになりました。ですが、実用面では、いくつかの小さなベンチマークやサンプル的なデモを除けば、公的に研究されて公開された現実的なユースケースはほとんどありません。
そこで、WebAssemblyがその約束を果たすことができるという確信を持つために、次のレベルとして、実際のプログラムを移植することにしたのです。
Doom 3ゲームは、このための理想的な候補であると思いました。実在する大規模なC++プログラムであり、かつて成功したAAAビデオゲームであり、オープンソースコード(非常に良質であることが知られています)であると同時に、ゲームエンジンとグラフィックスの点ではリリースされた時点 — 2004年 — の最先端の技術であり、多くのデスクトップシステムをひざまずかせたことでも有名です。
もうひとつ、このゲームに注力しようと決定する上で重要なポイントとなった、非常に優れた特性もありました。それはidTech 4エンジンが、単一スレッドで実行可能な、おそらくは最も先進的なゲームエンジンのひとつである、ということです。別の言い方をすれば、今日のほとんどのエンジンがマルチCPUコアシステム用に設計されているのに対して、Doom 3は、シングルCPUコアシステムで実行するように設計された、最後の"ハイエンド"ゲームのひとつなのです。Web上ではマルチスレッド環境がまだ整っていないため(Spectre/Meltdownのセキュリティ脆弱性がおもな原因です)、シングルスレッドであることは、プロジェクト開始時から必須要件でした。
そのような理由から、2018年末に、Doom 3のWebへの移植を決心しました。そして最終的には、WebAssemblyが今後10年間、真剣に検討すべき技術であることを確信したのです。
InfoQ:D3はブラウザで実行するには非常に厳しいゲームだ、という話がありましたが、その理由は何でしょう?ネイティブのデスクトップオペレーティングシステムにあって、現在のデスクトップブラウザにはないパフォーマンスドライバは何ですか?
Doom 3は、ブラウザにとっては非常に要求の厳しいゲームです。1)それ自体が非常に要求の厳しいゲームであること、2)ネイティブビルドには存在しない、ブラウザ特有の制約下で実行する必要があること、がその理由です。
1)については、前の回答でも述べたように、単一の実行スレッドで動作して優れたクオリティレベルのグラフィックスを提供するため、それ自体が非常に要求の厳しいゲームなのです。これはつまり、フレーム毎16ミリ秒を維持しようとする場合に、ピクセル単位の動的な照明とリアルタイムシャドウ、骨格アニメーション、剛体物理学、AI、ネットワークなど、連続して実行する必要のある計算量が単純に膨大である、という意味です。
そのような状況下での2)に関する最初の制約は、何よりもまず、WebAssemblyが低レベルの仮想マシンである、ということです。最終的にはバイトコードが専用プログラムによって解釈されるのですから、独自のネイティブ命令セットを実行する汎用CPUのパフォーマンスには歯が立ちません!Just-In-Timeコンパイラを使用しない場合、これによるパフォーマンスヒットは少なくとも2倍になります(これはもちろん、私の個人的な観察による経験的数値です。このトピックに関しては、もっと正確な学術的研究があるかも知れません)。
2番目の制約は、もっと理解が難しいものです。Webのコンテキストにおいて、WebAssemblyの観点から見た場合、"外の世界"で起きることは多かれ少なかれ ... JavaScript,最終的にはブラウザとそのセキュアなサンドボックスに拘束されています。"外の世界"には、グラフィックスやオーディオAPIも含まれます。つまり、WasmコードがグラフィックAPIを呼び出しても、ネイティブビルドで使用されるグラフィックカードドライバが直接呼び出されるのではなく、正しい"Web API"を呼び出すための小さなJavascriptレイヤが毎回関与して、いくつかのチェックや検証を行った末に、ブラウザがそのWeb API呼び出しをグラフィックドライバ呼び出しに変換し、転送するのです。"安全なサンドボックス"を抜け出すには、コストが必要です。
これらはすべて、最終的に大きなオーバーヘッドを発生させます。そのため、CPUと"外の世界"の両方に大きなストレスをかけるプログラム(フレームごとに多くのグラフィックスAPI呼び出しを行うなど)にとっては、非常に厳しい状況になります。
InfoQ:WebAssemblyでブラウザに移植されたデスクトップゲームは、他にもありますか?そのパフォーマンスプロファイルは、DOOM3で達成したものと同じ程度なのでしょうか?
私の知る限り、2019年現在、Doom 3ほど要求の厳しい商用ゲームでWebに移植されたものは、まだ他にはありません。素晴らしい技術デモはいくつかありますが、完全なAAAゲームというものはないのです。ただし、Webをすべてチェックしている訳ではないので、私が知らないだけなのかもしれません!ですが、自惚れを承知で言うならば、完全な商用ビデオゲームの優れたゲーム移植実験といえるものとして、私が以前にWebAssemblyに移植したArx Fatalisがあります。これは2002年のビデオゲームなので、D3に比べるとかなり劣りますが、それでも非常に興味深いものです。http://wasm.continuation-labs.com/arxdemo/で、デモをテストすることが可能です。
この移植の背景となったストーリは、ある意味WebAssemblyの前身である、Portable Native Client(PNaCl)と呼ばれるテクノロジを使用して行った、ネイティブアプリケーションを実行する実験にまでさかのぼります。うまく動作しましたが、GoogleがWebAssemblyを優先してこのテクノロジを廃止すると決定したので、新たなテクノロジを学習する方法のひとつとして、WebAssemblyにポートを移行することに決めたのです。
InfoQ:将来的に最新のブラウザすべてに導入されるべきWebAssemblyの機能として、SIMDサポート、ダイナミックリンク、64ビットアドレス指定、OffscreenCanvasの中から選ぶとすればどれでしょうか?
WebAssemblyに私が重要だと思うのは、その中のどれでもありません :)
WebAssemblyランタイムを一時停止/再開する機能なのです。
その理由を短いインタビューで説明するのは難しいのですが、基本的には、完全な非同期環境であっても、典型的なC/C++の同期コードは必ず組み込まれている、ということです。そのようなはコードは、環境にうまくマッチしないことが少なくありません。同期I/O操作の実行など、通常ならば簡単なことでも、現時点では実現が難しいことがいくつかあります。
例えば"永続ストレージから大きなファイルを同期的に読み取る"(ディスクからゲームアセットを取得するなど)という操作は、Web上ではもはやできない、ということを認識しなければなりません。この極めて単純なことは、プログラミングの黎明期から当前のことと受け取られていましたが、現在では失われているのです!正直にいって、これは痛いところです。
この問題を処理する方法はいくつかありますが、すべてコストがかかります。人為的に(ブラウザータブを含む)"すべてをブロック"するというのは、Webではよいプラクティスではありません。すべてのファイルシステム/アセットをRAMに保存する(永続ストレージソリューションのサイズを考慮すれば無駄である)というようなコストを要する回避策に頼るか、コードに対する重要な要件やコンパイルされたバイナリへの影響を承知の上で、特別なコンパイルフラグを使用するか、ということになります。
もちろん、同期コードを非同期コードに書き換えるのが最善の解決策ですが、Doom 3などの巨大なコードベースでは、合理的な時間でそれを行うのは不可能です。
そこで、WebAssemblyランタイムを一時停止/再開することができれば、25年以上前から使用されている同期I/Oパラダイムの一部を再導入できるようになるのです(少なくとも、C/C++コードの観点からは"同期"です)。
幸いなことに、Emscriptenプロジェクトを支援している人たちが、"Asyncify"や"Emterpreter"などといった面白い名前で、この問題に対処可能なさまざまなソリューションに、コンパイラ側から取り組んでくれています。Doom3ポートでも、移植プロセスを簡単にするために、それらを少し使用しました。次のイテレーションはおそらく"Bysyncify"と呼ばれるようになるでしょう。テストするのが楽しみです。
先程のリストからひとつを選ぶのならば、Offscreen Canvasを選択します。これはWebAssemblyとは関係ありませんが、この機能をまだ実装していないブラウザ実装(特にSafari)に関係します。しかし、実をいうと、この"選択"は先程のポイントに関連しているのです。Offscreen Canavanを使用すれば、グラフィカルアプリケーションのメインのWebAssemblyコードをWeb Workerで実行できるようになります。Web Workerでは、同期/非同期の問題がずっと少なくなるのです。
InfoQ:移植はフルタイム作業で6~7週間を要し、タスクもかなり複雑だった、という説明がありました。開発者はブラウザに主要なアプリケーションを移植する実験をすぐに始めるべきですか、あるいは技術が成熟するのを待つほうが賢明でしょうか、意見を聞かせてください。
テクノロジ自体は非常に成熟していると感じていて、それには非常に感銘を受けました。実際のところ、WebでCPUを集中的に使用するアプリケーションが必要な場合、WebAssemblyを採用しない理由はまったくありません。ビデオゲーム、CADソフトウェア、ビッグデータなどがそうです。現在は、3D CADソフトウェアでのWebAssemblyの使用法をデモするための長期プロジェクトに取り組んでいますし、先日は、ビッグデータに関連する将来的な製品に関する契約を行いました。現時点では詳細を話すことはできませんが、2020年には、Wasmに関連した素晴らしいサプライズがたくさんあることは間違いありません :)
さらに、WebAssemblyエコシステムに携わる人たち(コンパイラ、Wasmランタイム、またはコンパイル環境)が、それぞれの分野でスキルを積み上げてきていますので、将来的には、非常に優れたソフトウェアプラットフォームを期待できます。
ただし注意が必要なのは、WebAssemblyを使用したWebは、技術的なスタックを学ぶのが難しく、未完成な部分があり、依然として非常に変化の激しいターゲットだ、ということです。この最後のポイントは、プラットフォームに関する詳細な書籍を著すのがまだ難しい理由の説明にもなります。実際にできることはたくさんありますが、十分なお金/時間/知識のリソースが必要です。しかし、これにエネルギを費やす準備ができている人にとって、失望するものではありません!