GitHub Gems

PS2 Games Run in the Browser Through Static Recompilation

A GitHub project brings PlayStation 2 games to the web by translating their machine code into WebAssembly, with Gran Turismo 4 and God of War II as its first titles.

Gran Turismo 4 race running at full speed in a web browser on a laptop

A project published on GitHub is showing that PlayStation 2 games can run inside a web browser without an emulator. The repository, snuri00/ps2-web-recomp, translates the console's Emotion Engine machine code ahead of time into C++, compiles it to WebAssembly, and links it to a reimplementation of the PS2's operating system and hardware. According to the project description, Gran Turismo 4 already plays from boot through races at full speed in Chrome, and God of War II reaches combat with a steady 60 frames per second at the console's native resolution.

How the translation works

The core technique is static recompilation. Instead of interpreting a game instruction by instruction while it runs, a tool called eerecomp reads the game's executable, follows its control flow to identify functions, and writes C++ code for them in chunks of 16 KiB of guest code. The generated code has to preserve the quirks of the console's R5900 processor, including 128-bit registers, branch delay slots, and a floating point unit that rounds differently from the IEEE standard that most computers follow.

The PS2's operating system is handled differently. The EE side is answered by high-level emulation covering threads, semaphores, interrupt handlers, alarms and the channel that links the main processor to the I/O processor. The I/O processor runs the game's own driver modules from the disc, including sound, disc streaming, controllers and memory cards, on an interpreter of its R3000 CPU. The disc itself is read over HTTP Range requests, so only the executable has to be downloaded before the game starts.

Much of the 3D work in PS2 games happens in small programs, called microprograms, that run on vector unit 1. The project models their arithmetic bit for bit and includes the pipeline delays that games depend on. Programs seen during a test run are compiled ahead of time, while any new ones met in the browser are translated into WebAssembly on the spot, which the project says takes a few milliseconds per program.

Making it fast enough for the browser

Speed was the main obstacle. The GitHub repository notes that the first race ran at only 3 frames per second when rendered natively with a software rasterizer and an interpreter for vector unit 1. Moving the Graphics Synthesizer's video memory onto the GPU with WebGPU compute shaders, and compiling the vector unit programs, raised that to about 70 frames per second natively. The project's own account suggests that most of the remaining problems came from how the browser handled the work, not from the emulated hardware itself.

One example involved draw calls. The first GPU renderer submitted around 650 compute dispatches per frame, because every texture upload and palette load split the batch of triangles. Reordering the uploads so that they ran ahead of the triangles that did not depend on them, with the same output, cut the number to about 80. A separate cache of 16 MB for recently uploaded content reduced how much data crossed from WebAssembly to the GPU, since Gran Turismo 4 uploads the same 3 MB of textures every frame of a race.

  • Rendering at three times the native resolution initially dropped to 23 frames per second.
  • Shader changes and writing each frame's data in a single piece brought that setting to 48 to 50 frames per second on the same integrated GPU.
  • Nested timers in browsers are clamped to 4 ms, so the emulation loop now uses a MessageChannel to yield.
  • Moving emulation into a worker stabilised a race that had wandered between 40 and 50 frames per second.

A second game exposes new bugs

God of War II was brought up using the same scripts and needed no game-specific code. It did, however, uncover problems that Gran Turismo 4 had never triggered. The project lists two bugs, one in the recompiler and one in the vector unit's timing, along with several missing pieces of the I/O processor.

At first the game was silent, because its sound driver relies on a hardware timer in the I/O processor that had not been implemented. Later, a crash traced back to the recompiler. When a branch was the last instruction of a 16 KiB unit, the path that did not take the branch continued at the wrong place, running an instruction twice or running one that should have been skipped. Fixing that let the game reach combat. The remaining large polygons were traced to the vector unit model, which made clip flags visible one instruction too late for God of War II's microcode, a timing that the first game never exposed.

The repository says the game now plays from the menus through its cutscenes into combat. At twice the native resolution in Chrome, it runs at between 48 and 60 frames per second, limited by the laptop's integrated graphics chip.

What readers need to know before trying it

The project does not distribute any game code or data. Users must supply a disc image of a game they own, and the included port.sh script converts it into a web page on their own machine. The repository estimates about 300 MB of disk space per game and says God of War II went from disc image to page in three and a half minutes on an 8-core laptop. The tools required include git, CMake, Ninja, a C++20 compiler and Python 3, and the project has so far been run only on Linux on x86-64.

The browser also matters. The page needs WebGPU for its GPU renderer. Chrome and Edge support it on Windows and macOS, while on Linux Chrome and Chromium require flags to be enabled. Without WebGPU, the software renderer is fine for menus but too slow for 3D. Saves are kept in the browser's storage and can be exported as .ps2 files in the layout used by PCSX2, the widely used PS2 emulator. The page also requires cross-origin isolation headers, which the included server script provides.

The project is candid about its limits. Only two games have been brought up so far. Another title is likely to stop at an unimplemented system call or I/O processor library function, or at a graphics feature the renderer does not yet handle. The repository also warns that the generated code and built WebAssembly are translations of the original executable, and should be kept private rather than published. The project states that it is not affiliated with Sony or any game publisher.

For readers following browser-based game preservation, the work shows how far WebAssembly and WebGPU can now go in running demanding 3D software. Whether more PS2 titles follow will depend on how much of the console's remaining hardware and system behaviour the project can reproduce in the browser.

Source: GitHub

Comments (0)