世界を動かす技術を、日本語で。

HNに表示: PS2ゲームを静的に再コンパイルしたWebAssembly

2026年10月12日原文(github.com)

概要

  • PlayStation 2ゲームを エミュレータなし でブラウザ上で動作可能
  • ゲームの Emotion Engine機械語 をC++へ変換し、WebAssemblyとして実行
  • PS2のOSやハードウェアを WebGPU で再実装
  • Gran Turismo 4やGod of War IIなど 高負荷タイトル の動作実績
  • ユーザー自身の ディスクイメージ を変換し、ブラウザでプレイ可能

PS2ゲームのブラウザ実行技術概要

  • エミュレータ不要 でPS2ゲームをブラウザ上で動作させる新方式
  • ゲームの Emotion Engine(EE)機械語 を事前にC++へ変換
  • 変換後のC++を WebAssembly としてコンパイルし高速実行
  • PS2のOS・ハードウェアを 高レベルで再実装 し、WebGPUで描画処理
  • PSP版の psp-web-recomp と同様の手法を採用

Gran Turismo 4の動作実績

  • Gran Turismo 4 を最初の動作対象に選定
    • PS2で最も負荷が高いゲームの一つ
    • ベクトルユニットや浮動小数点演算、独自のグラフィック技法を多用
  • ブラウザ上で 起動~オープニング・メニュー・レース まで完全動作
  • 音楽・効果音・メモリーカード保存もサポート
  • Chrome+ノートPC内蔵GPU でPS2の2倍解像度・50fps(PAL版)を達成

God of War IIの移植と課題

  • God of War II も同手法で移植
    • ゲーム固有のコード不要で動作
    • Gran Turismo 4では発生しなかった リコンパイラのバグ やベクトルユニットのタイミング不具合を発見・修正
    • I/Oプロセッサの未実装部分も追加
  • メニュー~カットシーン~戦闘 まで60fps(PS2解像度)で安定動作
  • 2倍解像度では48~60fps、GPU性能がボトルネック

技術詳細

  • 再コンパイル(Recompilation)

    • eerecompがゲーム実行ファイルを解析し、関数単位でC++に変換
    • PS2独自の128bitレジスタ、マルチメディア命令、浮動小数点の挙動も再現
    • スレッド切り替えもホストスタックを巻き戻して再現
  • PS2カーネル再実装

    • EE側OSはスレッド・セマフォ・DMA・VBLANK割り込みなどを高レベルで再現
    • I/OプロセッサはR3000エミュレータ上でゲームのIRXモジュール(サウンド、ディスク、コントローラー等)を動作
    • ディスクはHTTP Rangeリクエストで必要部分のみ取得
  • ベクトルユニット

    • 3D処理の大半はベクトルユニット1のマイクロプログラムで実行
    • MACやクリップフラグ、PS2独自の浮動小数点仕様をモデリング
    • 既知のマイクロプログラムはSIMD C++で事前コンパイル、未知は即時WebAssembly変換
  • グラフィックス

    • Graphics SynthesizerのVRAMをGPU上に再現
    • WebGPUのコンピュートシェーダでポリゴン描画
    • GSメモリ内で全処理を完結させ、PS2同様のグラフィック効果を再現
    • 内部解像度は1~3倍まで選択可能、ソフトウェアラスタライザも参照用に実装
  • スレッド管理

    • エミュレーションはWorkerスレッドで実行
    • ベクトルユニット1も専用Workerで並列処理
    • GSコマンドはリングバッファでGPUスレッドへ送信
  • サウンド・動画

    • SPU2を再実装(ADPCM、ADSR、DMAストリーミング対応)
    • 音声はAudioWorklet経由で出力
    • 動画はPS2のMPEG-2デコーダ(IPU)を再現

高速化の工夫と課題

  • 初期はソフトウェアラスタライザ+ベクトルユニットインタプリタで3fps
  • GSをWebGPU化し、ベクトルユニットをコンパイルで70fpsまで向上
  • テクスチャアップロードの最適化で1フレームあたりのデータ転送量を60%削減
  • 3倍解像度時のパフォーマンス低下はシェーダの分岐やアップロード処理の改善で48~50fps達成
  • setTimeoutの遅延回避やWorkerスレッド活用でフレーム安定化

ゲーム移植手順

  • 必要環境: git, CMake, Ninja, C++20コンパイラ(clang推奨), Python3, 7-Zip

  • Linux(x86-64)上で動作確認済み

  • Emscripten SDKとwgpu-nativeを自動インストール

  • ディスクイメージを scripts/port.sh で変換し、C++変換とビルドを自動実行

  • 実行時に未検出関数やマイクロプログラムを追加し、動作範囲を拡張

  • 完了後、 build/web-ゲーム名 にWebページ、 build/native-ゲーム名 にネイティブバイナリを生成

    • 例:
      • git clone https://github.com/snuri00/ps2-web-recomp.git
      • cd ps2-web-recomp
      • scripts/port.sh mygame "My Game.iso"
      • python3 scripts/serve.py build/web-mygame games/mygame/disc.iso
      • ブラウザで http://localhost:8620/ にアクセス
  • port.shはISO/ZIP/7z形式のディスクイメージに対応

  • 静的解析と複数回の自動実行により、必要なコード・マイクロプログラムを網羅的に変換

  • --pressや--framesオプションで自動入力や実行フレーム数を調整可能

  • build_web.shでページのみ再ビルドも可能

動作環境・ブラウザ

  • WebGPU が必要(Chrome/EdgeのWindows・macOSは標準対応、Linuxはchrome://flags/#enable-unsafe-webgpu等で有効化)
  • WebGPU非対応時はソフトウェアレンダリングに自動切替(3Dは非常に遅い)
  • ノートPCのデュアルGPU環境では描画アダプタの自動切替・フレームコピー機能あり
  • キーボード操作:Z(×)、X(〇)、A(□)、S(△)、Q/W/1/2(L/R)、Enter(Start)、Backspace(Select)、矢印キー(Dパッド)、IJKL(左スティック)
  • Gamepad API対応、アナログトリガーや振動もサポート(Chrome/Edge)
  • スマートフォンはオンスクリーンコントローラ対応、Fでフルスクリーン切替
  • 解像度変更はページ再読み込みで反映

ネイティブ実行

  • build/native-mygame/ps2run でSDL2ウィンドウ上にゲームを表示
  • Vulkan経由でwgpu-nativeを使用、サウンドはSDL経由
  • キーボードやSDL対応ゲームコントローラで操作可能
  • scripts/port.sh mygame "My Game.iso" --native-onlyでネイティブバイナリのみビルド可能

制約・注意事項

  • ゲームデータは ユーザー自身が所有するディスクイメージ を用意
  • 対応ゲームは現時点で2タイトルのみ、他ゲームは未実装のシステムコールやライブラリ関数、GS機能で停止する可能性
  • ログには未対応システムコールやライブラリ名が表示される
  • 実験的プロジェクトのため、動作保証やサポートは限定的

Hackerたちの意見

グランツーリスモを長いCD読み込み画面なしでプレイしたい人なんているの?

└

それ、簡単にシミュレートできるよね?ゲームを手動で一時停止して、立ち上がってサンドイッチ作って、食べて、犬を外に連れて行って、ブロック一周散歩させてから、トイレに行って、また再開するって感じで。全然心配いらないよ。

└

それに、起動時に必要な「息を止める瞬間」もないしね。DVDがちゃんと読み込まれたか音を聞いて確認するあの瞬間。約1秒間、時間が止まったかのように感じて、「ビュンプ」って音が聞こえて、世界が大丈夫だってわかるまで。

└

トラックマニアみたいなリロード時間でゲームができたら最高だよね(トラックマニアでレースを再スタートすると、すぐにスタートラインに戻れるから)。でも、GTやNFSのゲームには追加のパッチが必要だろうけど…。

└

もっといい質問だね:グランツーリスモ3や4を圧力感知コントローラーなしでプレイしたい人なんているの?オリジナルのPS2やPS3のコントローラーをPCSX2で使っても、PS2のスムーズな加速やブレーキカーブは再現できないよ。キーボードや完全デジタル入力でプレイするのは、本当に miserable な体験だよ。

└

それに、音響エラー処理も失われるしね:一つのシーク音はresolve()を意味し、もう一つはreject()を意味してた。

└

「グランツーリスモをプレイしたい人なんているの?」 [準備中...] 「長いCD」 [準備中...] 「読み込み画面なしで?」

このリコンパイルの話は本当にすごいね。AIが自分の職業を変えちゃったのはあんまり好きじゃないけど、少なくとも何か良いものを得てるからいいかな。

└

同じく笑。だけど、これのおかげでSteam Deckでボタン一つでXbox 360版のNFSモストウォンテッドを完璧にプレイできてるから、小さな勝利を楽しんでるよ。オリジナルのフォルツァホライゾンも動いてるって聞いたから、テンション上がってる。

└

このリポジトリにはAIについての言及は全くないね。

コンパイラをWebAssemblyにコンパイルして、どこでもホストできるようにして、ブラウザから直接プロジェクトを変換するのはどう?

└

そうだね、ここに行くべきだと思う。リコンパイラ自体は普通のC++で、wasm用に簡単にビルドできるんだ。重い部分はその出力をコンパイルすることで(GoW2は約670k行のCppになる)、ブラウザでclangを動かす必要がある。もっといい方法は、リコンパイラが直接WebAssemblyを出力して、ブラウザのエンジンにコンパイルさせることだね。AOTで見られなかったVU1マイクロプログラムに対しては、もうそれをやってるよ。配布の問題も解決するし、自分のISOを選んで、変換はローカルで行われるから、ゲームから派生したものはホストされないんだ。

Hacker Newsで議論の続きを見る