PS2 游戏在浏览器里跑:不是模拟器,是”静态重编译”

· 科技资讯

PS2 游戏在浏览器里跑:不是模拟器,是”静态重编译”

一个开源项目把 PS2 游戏直接”翻译”成了 WebAssembly,在浏览器里以原生速度运行——没有模拟器,没有逐条指令解释执行,而是把 Emotion Engine 的机器码提前转成 C++,再编译成 WASM。Gran Turismo 4 在笔记本集显上以两倍 PS2 分辨率跑出 50 帧,God of War II 在重度战斗中稳定 60 帧。这个项目在 Hacker News 上获得 257 分,技术深度远超”又一个模拟器”。

不是模拟,是”翻译”

传统 PS2 模拟器(如 PCSX2)的工作方式是:在 CPU 上逐条解释或动态重编译 Emotion Engine(EE)的指令。每一条 PS2 指令都要在运行时被”翻译”成 x86/ARM 指令,然后执行。这个过程有不可避免的开销。

ps2-web-recomp 走了一条完全不同的路:它在构建时(而不是运行时)读取游戏的可执行文件,追踪控制流找到函数,然后以 16 KiB 的粒度为每个函数块生成 C++ 代码。这段 C++ 保留了 R5900 的所有怪癖——128 位寄存器、多媒体指令、分支延迟槽、PS2 浮点单元(没有无穷大和非规格化数,舍入规则不同于 IEEE)、向量单元 0 作为协处理器使用。块之间的跳转变成 tail call,线程切换通过展开宿主栈并在客户地址处恢复,所以生成的代码不需要为每个客户线程维护独立栈。

生成的 C++ 被编译成 WebAssembly,链接到一个用 C++ 重实现的 PS2 操作系统和硬件层,图形渲染走 WebGPU。整个过程是”静态”的——游戏被一次性翻译,之后在浏览器里跑的是原生代码,没有解释器、没有 JIT、没有模拟开销。

PS2 → WebAssembly 静态重编译流程 PS2 游戏 EE 机器码 (你的光盘镜像) eerecomp 静态重编译 16KiB 粒度→C++ C++ → WASM 保留 R5900 浮点/向量怪癖 WebGPU 渲染 GS 光栅化 compute shader 浏览器 Chrome 实测性能:GT4 50fps @2x 分辨率 · God of War II 60fps 重度战斗 @1x · 集显 Chrome IOP R3000 用解释器 · 向量单元微程序 AOT 编译为 SIMD C++ · SPU2 48 通道 ADPCM · 记忆卡存浏览器 MIT 许可 · 不含游戏数据 · 需自备光盘镜像

性能优化的”深水区”

这个项目的 README 里有一节叫”Lessons from making it fast”,读起来像一篇性能工程论文。初始版本在原生分辨率下只有 3 帧——软件光栅化 + 向量单元 1 解释器。把 GS 移到 WebGPU compute shader、把向量单元微程序编译成 SIMD C++ 后,跳到了约 70 帧。但”剩下的工作主要是关于浏览器把时间花在哪里,而不是模拟本身”。

几个关键的优化细节:GPU 渲染器最初每帧提交约 650 个 compute dispatch(因为每次纹理上传和调色板加载都会打断三角形批次),通过把不依赖三角形的上传提前执行,降到了约 80 个。Gran Turismo 4 每帧上传同样的 3 MB 纹理,由于 GS 内存每帧交换,不能简单跳过——但一个 16 MB 的 GPU 端缓存让大部分上传不需要再从 WASM 跨越到 GPU,每帧数据传输量削减了约 60%。

三倍分辨率下帧率掉到 23。剖析 shader 发现每三角形设置在一个线程间分支之后加载,导致整个 setup 分支发散(divergent),而且 1 MB 分片的上传阻塞了 Chrome 的页面线程。把 setup 统一加载、每帧数据一次性写入后,三倍分辨率恢复到 48-50 帧。甚至浏览器的 `setTimeout` 嵌套调用被限制在 4 ms,导致模拟循环在 40-50 帧之间波动——改用 `MessageChannel` 让出、把模拟放进 worker 后,比赛稳定在 50 帧。

两个游戏验证了通用性

第一个跑通的游戏是 Gran Turismo 4,选择它是因为它是 PS2 上最 demanding 的游戏之一:重度依赖两个向量单元、依赖精确浮点行为(回放和 license 测试)、使用从渲染图像读回调色板的图形技巧。它从启动到开场动画、菜单、比赛全程可玩,有音乐和音效,记忆卡存在浏览器里。

第二个是 God of War II,走同一套脚本,不需要任何游戏特定代码。但它触发了 GT4 从未碰到的两个 bug——一个在重编译器里,一个在向量单元时序里——以及 I/O 处理器的几个缺失部分。修复后,它从菜单到过场动画到战斗全程可玩,PS2 分辨率下 60 帧,两倍分辨率下 48-60 帧。

两个游戏的对比验证了项目的通用性:不是为特定游戏 hack 的,而是对 PS2 架构的通用重编译。但作者也很诚实:”目前只跑通了两个游戏。另一个游戏很可能卡在某个没人实现的系统调用或 IOP 库函数上。”

这对游戏 preservation 意味着什么

PS2 拥有 3800 多款游戏,其中大量从未在 PC 上发售。传统模拟器的路径是”在 PC 上装 PCSX2 → 放光盘镜像 → 跑”,门槛不低。ps2-web-recomp 把路径变成了”浏览器打开一个网页 → 游戏就跑起来了”,而且不需要装任何东西。WebGPU 的浏览器支持正在快速普及(Chrome/Edge 在 Windows 和 macOS 上已默认开启),这意味着 PS2 游戏的”浏览器化”可能比预想的更快。

更重要的是方法论:静态重编译到 WASM 的思路可以推广到任何”指令集架构相对固定、游戏数量庞大”的平台。作者已经在 PSP 上做了同样的事(psp-web-recomp)。如果 N64、GameCube 甚至 Dreamcast 也能走这条路,游戏 preservation 的门槛将大幅降低——不需要装模拟器,打开浏览器就能玩。

当然,这个项目目前只有 2 个 star、1 个 fork、114 个 commit,是一个个人项目。它的价值不在于”能玩多少游戏”,而在于证明了”PS2 游戏在浏览器中以原生速度运行”这件事在技术上是可行的。剩下的问题是规模——有多少款游戏能跑通,需要多少工程投入。

核心观点:ps2-web-recomp 的真正贡献不是”PS2 游戏能在浏览器里跑了”,而是证明了”静态重编译到 WASM + WebGPU”可以替代传统模拟器,在浏览器中达到原生帧率。如果这套方法论能推广到 N64/GameCube/Dreamcast,游戏 preservation 将从”装模拟器”变成”打开网页”。关注这个项目,也关注 WebGPU 的浏览器覆盖进展——这是”浏览器成为游戏主机”的关键拼图。

— END —

LC 智趣厅 · 科技与生活的交点

ihygg.cn

Scroll to Top
微信公众号:LC智趣厅

扫码关注微信公众号
LC智趣厅