Static recompilation runtime libraries for PlayStation 3 titles. Turn PS3 binaries into native executables. No emulator required.
Join the sp00nznet recomp Discord — the community hub for sp00nznet's recomp projects, where ps3recomp development happens in the open. Good place to ask questions, show a port you are working on, or find out what people are stuck on before you duplicate the effort.
ps3recomp is an open-source toolkit that provides the runtime libraries, system stubs, and analysis tools needed to statically recompile PlayStation 3 games into native PC executables.
Instead of interpreting or dynamically recompiling PowerPC/SPU instructions at runtime (what emulators like RPCS3 do brilliantly), we take the opposite approach: translate everything ahead of time into C/C++ that compiles with your favorite compiler on any modern platform.
This is the same philosophy behind:
- N64Recomp (N64 -> native)
- UnleashedRecomp (Xbox 360 -> native)
- PS2Recomp (PS2 -> native)
- burnout3 (Original Xbox -> native)
- ReXGlue (Xbox 360 -> native)
- AnyPS5 (PS5 -> native)
...but for the PS3's glorious, terrifying Cell Broadband Engine.
The PlayStation 3 has over 3,000 titles and some of the most beloved games ever made. RPCS3 has done heroic work making ~70% of the library playable through emulation, but static recompilation offers something different:
- Native performance — no runtime translation overhead
- Lower hardware requirements — runs on mid-range PCs
- Moddability — recompiled C/C++ is infinitely more hackable than PPC binaries
- Preservation — native ports survive long after emulators stop being maintained
- Portability — the output is C/C++, so it can target any platform a compiler does (see platform support for where the runtime actually stands today)
CI builds and tests every row on every pull request: Windows (clang-cl), macOS arm64, Linux (GCC and Clang), and Linux with the Vulkan backend on lavapipe under the validation layer. A green check means the runtime built and the tests passed. It does not mean a game ran; the last row is the only one that claims that.
| Windows | macOS (arm64) | Linux | |
|---|---|---|---|
| Runtime library builds | yes | yes | yes |
| Lifter test suites + C unit tests | yes | yes | yes |
| Render backend | D3D12 | Metal | Vulkan (opt-in); null (headless, CI) |
| Runs a recompiled game, in this tree | yes | no | no |
What stops macOS and Linux running a title is the PPU boot scaffold.
ppu_loader.cpp, boot_main.cpp and the HLE dispatch are compiled per game,
not into the library. They compile on POSIX with zero errors (a CI ratchet
keeps it that way) and the frame clock runs there, but no title has yet been
booted to gameplay from this tree on either OS.
The renderers are further along than that. ps3recomp_host drives cellGcm
→ RSX → backend end to end with no game. With guest programs on, Metal and
Vulkan both run the title's own shaders on the shared register-file draw
engine. Every ps3recomp_host scene passes on both, including render-to-texture,
MRT, depth textures, cube maps and stencil. Linux's default stays the headless
null backend, a CPU triangle filler that CI draws with.
Downstream, people are already past this. Twisted Metal's menus run on Linux/Vulkan, inFamous on macOS, and Killzone 3 under Proton (see In the community). Those ports carry patches that are still on their way upstream, which is why the table still says "no".
The PS3's Cell processor is a beast unlike anything else:
| Component | What It Is | Why It's Hard |
|---|---|---|
| PPU | PowerPC 64-bit main CPU | Custom ISA extensions, VMX/AltiVec SIMD |
| 6x SPU | 128-bit SIMD vector processors | Proprietary ISA, 256KB local store, explicit DMA |
| Memory | 256MB XDR RAM | 128-byte alignment requirements, split bus |
| LV2 Kernel | Proprietary OS layer | ~300+ system calls, complex threading model |
| PRX Modules | Dynamic libraries | 100+ system libraries with intricate interdependencies |
We don't shy away from hard problems. We just break them into smaller ones.
ps3recomp/
├── tools/ # Binary analysis & recompilation pipeline
│ ├── elf_parser.py # Parse PS3 ELF/SELF/PRX binaries
│ ├── ppu_disasm.py # PowerPC disassembler with PS3 extensions
│ ├── ppu_lifter.py # PPU assembly -> C code lifter
│ ├── spu_disasm.py # SPU instruction set disassembler
│ ├── spu_lifter.py # SPU assembly -> C code lifter
│ ├── extract_spu_images.py # Extract embedded SPU images from PRX/ELF
│ ├── find_spu_functions.py # SPU function boundary detection
│ ├── wrap_spu_elf.py # Wrap a raw SPU blob as a loadable ELF
│ ├── prx_analyzer.py # Analyze PRX imports/exports and NIDs
│ ├── nid_database.py # Function Name ID (NID) resolver
│ ├── find_functions.py # Function boundary detection
│ └── generate_stubs.py # Generate HLE stub skeletons from a NID list
│
├── runtime/ # Core runtime for recompiled executables
│ ├── ppu/ # PPU execution context
│ │ ├── ppu_context.h # Register file, CR, LR, CTR, FPSCR
│ │ ├── ppu_memory.h # Memory access macros (loads, stores, byte-swap)
│ │ └── ppu_ops.h # Instruction operation macros
│ ├── spu/ # SPU execution context
│ │ ├── spu_context.h # 128×128-bit register file, 256KB local store, image_id
│ │ ├── spu_channels.c # Channel ops + per-image function-table dispatch
│ │ ├── spu_helpers.h # SPU intrinsics (incl. float conversions)
│ │ ├── spu_dma.h # DMA (MFC) transfer engine
│ │ └── tests/ # Self-contained SPU runtime tests
│ ├── memory/ # Memory subsystem
│ │ └── vm.h # Virtual memory manager (256MB address space)
│ └── syscalls/ # LV2 kernel system call implementations
│ ├── sys_ppu_thread.h # Thread creation/management
│ ├── sys_mutex.h # Mutex/cond synchronization
│ ├── sys_memory.h # Memory allocation/mapping
│ ├── sys_fs.h # Filesystem operations
│ └── lv2_syscall_table.h # Full syscall dispatch table
│
├── libs/ # HLE library implementations
│ ├── audio/ # cellAudio, cellAdec, libmixer, libsnd3, libsynth2
│ ├── video/ # cellGcmSys, cellResc, cellVideoOut, cellVpost, cellVdec
│ ├── input/ # cellPad, cellKb, cellMouse
│ ├── hardware/ # cellGem, cellCamera, cellUsbd
│ ├── network/ # cellNetCtl, cellHttp, cellHttps, cellSsl, sceNp*
│ ├── filesystem/ # cellFs, cellGame, cellSaveData, cellStorage
│ ├── system/ # cellSysutil, cellSysmodule, cellRtc, sysPrxForUser
│ ├── spurs/ # cellSpurs, cellFiber, cellSpursJq, cellDaisy (SPU task management)
│ ├── sync/ # cellSync, cellSync2 (cross-PPU/SPU synchronization)
│ ├── codec/ # cellJpgDec, cellPngDec, cellGifDec, cellPamf, cellDmux, cellAdecAtrac3p, cellAdecCelp8, cellVdecDivx
│ ├── font/ # cellFont, cellFontFT, cellFreeType, cellL10n
│ └── misc/ # cellScreenshot, cellSubdisplay, cellImeJp, cellVideoExport, cellMusicExport, cellGameRecording, etc.
│
├── include/ps3emu/ # Public API headers
│ ├── ps3types.h # Fundamental PS3 types (u8-u128, s8-s64, be_t<>)
│ ├── endian.h # Big-endian <-> little-endian conversion
│ ├── nid.h # NID hashing and lookup
│ ├── module.h # Module registration framework
│ └── error_codes.h # PS3 system error codes (CELL_OK, CELL_E*)
│
├── templates/project/ # Starter template for new game ports
│ ├── CMakeLists.txt # Build system
│ ├── main.cpp # Application entry point
│ ├── stubs.cpp # Game-specific function overrides
│ └── config.toml # Recompiler configuration
│
├── config/ # Reference configurations
│ └── example.toml # Example recompilation config
│
└── docs/ # See the Documentation table below
The pipeline follows the same proven approach as our burnout3 project, adapted for the Cell architecture:
PS3 Game Disc / PKG
│
▼
┌─────────────┐
│ SELF/EBOOT │ Encrypted PS3 executable
│ Decryption │ (requires keys / fSELF)
└──────┬──────┘
│
▼
┌─────────────┐
│ ELF Parser │ Extract sections, segments, relocations
│ + PRX Scan │ Identify imported NIDs & library deps
└──────┬──────┘
│
▼
┌─────────────┐
│ PPU Disasm │ Disassemble PowerPC 64-bit + VMX
│ + Analysis │ Function boundaries, jump tables, ABI
└──────┬──────┘
│
▼
┌─────────────┐
│ PPU Lifter │ PowerPC → C code generation
│ + SPU Lift │ SPU programs → C code generation
└──────┬──────┘
│
▼
┌─────────────┐
│ Link with │ ps3recomp runtime + HLE libs
│ Runtime │ Provides all PS3 OS services
└──────┬──────┘
│
▼
┌─────────────┐
│ Compile & │ MSVC / GCC / Clang
│ Ship! │ Native x86-64 executable
└─────────────┘
The SPU is the elephant in the room. Each SPU has its own instruction set, its own 256KB memory, and communicates with the PPU via DMA and mailbox channels. Our approach:
- SPU programs are self-contained — they live in ELF segments loaded to local store (
extract_spu_images.pypulls them out of PRX/ELF) - Recompile each SPU program separately — dedicated
spu_disasm.py+spu_lifter.pyhandle the SPU ISA - SPU local store becomes an array — 256KB per "virtual SPU"
- DMA operations become memcpy — via the MFC engine (
spu_dma.h) - Channels become cross-thread message queues — preserving ordering guarantees
- Per-image function-table dispatch —
image_idlets multiple SPU programs (e.g. a SPURS kernel, a policy module, and a job) coexist at overlapping local-store addresses
This mirrors how RPCS3 handles SPU but at compile time rather than runtime. The
disassembler, lifter, and runtime are functional and covered by self-contained
tests (runtime/spu/tests/: sum, shufb, DMA, brsl-return).
HLE implementations of the PS3 system libraries, written for this project. RPCS3 is a behavioural reference, not a code source. Most modules are complete. The ones still marked Partial are the media decoders (cellVdec, cellAdec, cellDmux, cellAtrac, cellAdecAtrac3p) and cellSpurs. docs/MODULE_STATUS.md has one row per module and is the source for the counts.
| Category | Modules | Status |
|---|---|---|
| Kernel Threading | sys_ppu_thread, sys_mutex, sys_cond, sys_semaphore, sys_rwlock | ✅ Complete |
| Kernel Events | sys_event (queues, ports, flags), sys_timer | ✅ Complete |
| Kernel Memory | sys_memory, sys_mmapper (containers, shared mem) | ✅ Complete |
| Kernel Filesystem | sys_fs (path mapping, real I/O) | ✅ Complete |
| Filesystem | cellFs (real file I/O, dir ops, stat, path translation) | ✅ Complete |
| Save System | cellSaveData (callback-driven, PARAM.SFO), cellGame | ✅ Complete |
| Input | cellPad (XInput/SDL2), cellKb, cellMouse | ✅ Complete |
| Audio | cellAudio (WASAPI/SDL2, mixing thread, multi-port) | ✅ Complete |
| Video Output | cellVideoOut (resolution config, 720p default) | ✅ Complete |
| Codecs | cellPngDec, cellJpgDec, cellGifDec (stb_image) | ✅ Complete |
| Font | cellFont (stb_truetype backend + fallback metrics) | ✅ Complete |
| Network | sys_net (BSD sockets, P2P), cellNet, cellNetCtl, cellHttpUtil, cellSsl, sceNp*, sceNpTrophy, sceNpMatching2 + Score over psnr | ✅ Complete |
| Hardware | cellUsbd (USB), cellCamera (PS Eye), cellGem (PS Move) — stub, no devices | ✅ Complete |
| Sync | cellSync (atomic spinlocks, LF queue), cellSync2 (OS-backed) | ✅ Complete |
| System | cellRtc, cellMsgDialog, cellOskDialog, cellUserInfo, cellGameExec | ✅ Complete |
| Localization | cellL10n (UTF-8/16/32/UCS-2, ISO-8859-1, generic converter) | ✅ Complete |
| Resolution | cellResc (display modes, scaling, interlace, aspect ratio) | ✅ Complete |
| Fibers | cellFiber (PPU fiber scheduler via Windows Fibers/ucontext) | ✅ Complete |
| AV Config | cellAvconfExt (audio output info, gamma, sound availability) | ✅ Complete |
| Input Util | cellKey2char (HID scancode → Unicode, US-101 layout) | ✅ Complete |
| Graphics | cellGcmSys (cmd buffer, IO mapping, tile/zcull, flip handlers, timestamps, FIFO walker + ring recycle), RSX command processor (NV47xx parsing, state tracking, backend callbacks), live D3D12 backend (executes the title's real NV4097 vertex/fragment programs — indexed draws, per-draw VP constants + textures, render-to-texture, MRT, FP predication), null backend (Win32 window) | ✅ Complete |
| SPURS | cellSpurs (management APIs, event flags, task/workload tracking), cellSpursJq (job queues with wait/signal), cellDaisy (real ring buffer FIFO) | ✅ Complete |
| Core Runtime | cellSysutil (BGM, cache, disc), cellSysmodule, sysPrxForUser (real lwmutex/lwcond/threads) | ✅ Complete |
| Media Pipeline | cellPamf (PAMF header + stream descriptors), cellDmux (callback sequencing), cellVdec (H.264/MPEG-2 through FFmpeg loaded at run time, opt-in), cellAtrac (ATRAC3plus, all-in-memory), cellAdec (callbacks, no decode yet), cellSail (state machine) | 🔨 Partial |
| HTTP/HTTPS | cellHttp (real HTTP/1.1 via native sockets), cellHttps (TLS stub with cert management) | ✅ Complete |
| Misc/Export | cellSubdisplay, cellImeJp, cellVideoExport, cellMusicExport, cellPhotoExport/Import, cellGameRecording, cellPrint, cellRemotePlay | ✅ Complete |
Full status tracking: docs/MODULE_STATUS.md
We've written extensive docs covering every aspect of the project. Whether you're contributing, porting a game, or just trying to understand how PS3 static recompilation works, there's a doc for you.
| Document | What It Covers |
|---|---|
| Getting Started | Prerequisites, installation, first recompilation walkthrough |
| Architecture | Cell processor overview, recomp pipeline stages, memory model, comparison with RPCS3 |
| Building | CMake build system, compiler support, platform-specific notes, troubleshooting |
| Game Porting Guide | Full 12-phase walkthrough for porting a PS3 game — with flOw case study |
| Custom Modules | Step-by-step tutorial for writing new HLE modules — NID system, calling convention bridge, patterns |
| FAQ & Troubleshooting | Common questions, build errors, runtime crashes, lifter issues, performance tips |
| Contributing | Development setup, code style, PR guidelines, ways to contribute |
| Runtime Reference | Virtual memory manager, PPU/SPU execution contexts, type system, endianness, syscall dispatch, DMA engine |
| Syscall Reference | All LV2 kernel syscalls: threading, sync, events, timers, memory, filesystem |
| NID System | How PS3 function linking works, NID computation, module registration framework |
| Module Reference | Detailed documentation for every HLE module — what they do and how they're implemented |
| Module Status | Quick-reference status table for all modules |
| RSX Graphics | RSX GPU translation architecture: command processor, D3D12 and Metal backends, shader strategy |
| Tools Reference | Every recompiler pipeline tool documented: ELF parser, disassembler, lifter, NID database |
| SPU Lifter | SPU ISA decoding/lifting, the runtime model (local store, channels, DMA, per-image dispatch), and the SPU tests |
| Platform Abstraction | How we handle Win32 vs POSIX: threading, sockets, timers, audio, memory, fibers |
| SPU Fallback | The PPU-side fallback registry — a hand-written replacement for an SPU job, or a bring-up shim before an image is lifted |
| Debug Console | Ask a title that is already running what it is doing, without a rebuild |
| Runtime Diagnostics | Generated index of every diagnostic environment variable the runtime reads |
| Prototype & Debug Builds | Why unencrypted, symbol-bearing prototype builds are the pipeline's ground truth |
| Online Play | Matchmaking, leaderboards and P2P play through a psnr server — --psnr host --username NAME |
| Regression Gate | How five ports are checked against recorded goldens before a shared-runtime change lands — and how to tell a real red from the four kinds of measurement artefact |
Downloads: each release
includes a prebuilt SDK bundle per platform (ps3recomp-<version>-win-x64.zip,
-mac-arm64.zip, -linux-x64.zip) plus SHA256SUMS.txt. A bundle contains the
runtime library, its headers and the Python pipeline. VERSION.txt inside it
says what that platform can and cannot do yet.
Prerequisites (building from source): Python 3.10+ (CI uses 3.12), CMake 3.20+, Ninja, and a C17/C++20 compiler: clang-cl with Visual Studio 2022 on Windows (plain MSVC builds the runtime library, but lifted game code needs clang-cl), GCC or Clang on Linux, Apple Clang (Xcode) on macOS. CI builds with the compilers on GitHub's
windows-latest,ubuntu-latestandmacos-14runner images; no older compiler version is tested.
git clone https://github.com/sp00nznet/ps3recomp.git
cd ps3recomp
pip install -r requirements.txt
# Stage 1: image, OPD function table, TOC and firmware imports
python tools/ppu_loader.py /path/to/EBOOT.ELF -o out/
# Stage 2: lift to C++. --hle-stubs turns each firmware import stub into
# ps3_hle_call(nid); leave it out and the first import call crashes the port.
python tools/ppu_lifter.py /path/to/EBOOT.ELF \
--functions out/EBOOT.functions.json \
--hle-stubs out/EBOOT.imports.json \
--output templates/project/recompiled/
# Stage 3: the NID -> HLE handler table, next to the lifted code
python tools/gen_hle_nids.py --all --out templates/project/recompiled/ppu_hle_nids.cpp
# Build the port from the template (RECOMP_DIR defaults to ./recompiled)
cd templates/project
cmake -B build -G Ninja
cmake --build buildSee docs/GETTING_STARTED.md for the full walkthrough.
Status as of 2026-10-12. Each port's own README carries the live detail and the run recipe.
| Game | Title ID | Status | Repo |
|---|---|---|---|
| The Simpsons Arcade Game (Konami) | NPUB30563 | Playable, and playable online. Boots through the Konami intro and character select into Stage 1, Downtown Springfield, with its ATRAC3plus music (#186) and correct flashes and glyphs (#185). Two players meet over psnr and play a match together: lobby, character select, the host's game setup, then Stage 1 in sync on both machines with each player's input moving their character on both screens — including with one player behind a NAT, through psnr's relay (#200, see docs/ONLINE.md). A Konami arcade emulator EBOOT: the 1991 coin-op ROM lives in SIMPSONS.SR and the binary emulates the hardware around it |
sp00nznet/simpsonsarcade-ps3 |
| Tornado Outbreak (Loose Cannon / Konami) | BLUS30371 | In game, rendering correctly with no per-title overrides. Logos and Bink intro, title, main menu, New Game (the save is created), the story intro and dialogue, then the first level under stick control at ~10–16 fps. The runtime fixes it needed — raw-SPU proxy DMA, vertex-program flow control, GPU resolve copies — are shared (#189) | sp00nznet/tornado |
Not under active development; they are where much of the runtime was first proven, and several stay in the regression gate.
| Game | Title ID | Where it got to | Repo |
|---|---|---|---|
| Virtua Fighter 5 (Sega AM2) | BLUS30020 | Renders its NOW LOADING, CRIWARE and AM2 screens; zero SPURS and zero PSN imports | sp00nznet/vf5 |
| Tokyo Jungle (Crispy's/SCE Japan) | NPUA80523 | Data install, SPURS jobs, title screen and the main menus | sp00nznet/tokyojungle |
| You Don't Know Jack (Jellyvision/THQ) | BLUS30569 | Menus and answerable quiz questions; movie-backed screens still draw noise | sp00nznet/youdontknowjack |
| Twisted Metal (Eat Sleep Play) | BCUS98106 | Drove the live NV4097 engine (#113); boots real game code and its asset install | sp00nznet/twistedmetal |
| flOw (thatgamecompany) | NPUA80001 | First draws with the real libsre.prx; assets load |
sp00nznet/flow |
| Rubber Ducky (Sony E3 2006 demo) | NPEA00003 | A debug build with full symbols — the lifter's ground truth, not a game target | sp00nznet/rubberducky |
Ports other people are running on ps3recomp, whose fixes come back upstream:
- inFamous (@NoahBPeterson): in game on macOS/arm64 at around 13 fps, booting on Sony's own liblv2 and libsre (LLE). Its exact SPU float and VMX work landed in v0.15.0 (#286, #287), and @erikomis's inFAMOUS 2 bring-up on the same branch sent six fixes (#311-#316).
- Twisted Metal (@Kurtisone): menus on Linux/Vulkan, the deferred renderer's lighting and post-FX included. Most of v0.14.0's draw-engine and Vulkan work came out of this port.
- Killzone 3 (@undecuple): all nine chapters load and run five minutes of scripted play, and one chapter has been played by hand to its end (Windows build, run under Proton). Its general fixes went upstream through #214 and the PRs that followed it.
- LittleBigPlanet (@sagemono), Yakuza: Dead Souls (@canersaka), God of War II HD and Ben 10 Omniverse (@andrebrumdev), and DBZ Budokai HD (@gnome41).
Ask in the Discord to get yours listed.
Want to port a game? Start with the Getting Started section, check docs/MODULE_STATUS.md for system library coverage, and see the Game Porting Guide for a real-world walkthrough.
| Project | Role |
|---|---|
| RPCS3 | Our primary reference for HLE module behavior and system call semantics. Standing on the shoulders of giants. |
| XenonRecomp | PowerPC recompiler for Xbox 360. Same ISA family and the same approach; our lifter is our own. |
| N64Recomp | Pioneered the modern static recomp approach. Our architecture follows the same "recompile to C, link with runtime" philosophy. |
| PS2Recomp | Sibling project for PS2. Different ISA (MIPS vs PowerPC) but same spirit. |
| ReXGlue | The closest sibling this project has: a static recompilation SDK for the Xbox 360, turning PowerPC into portable C++ compiled ahead of time rather than interpreted. Same shape as ps3recomp — a toolkit plus a runtime, with game ports built on top — and a generation of Xenon hardware away from Cell. Their release engineering covers five platforms from one reusable build workflow, with nightlies and tagged releases that publish artifacts. |
| pcrecomp | Our PC recompilation toolkit. Shared philosophy of "analyze → disassemble → lift → link → ship". |
- RPCS3: a behavioural reference for HLE modules and syscalls. We read what it does and then write our own. No RPCS3 (GPL) code belongs in this tree.
- Direct3D 12 / Metal / Vulkan: RSX graphics translation. D3D12 is the backend that runs games in this tree today. Metal (macOS) and Vulkan (Linux, opt-in, see docs/BUILDING.md) run guest shaders on the shared draw engine. CI draws with the headless null backend.
- SDL2: input and audio off Windows.
cellPadandcellAudioalways use their SDL2 backends on non-Windows hosts, so SDL2 is required there; on Windows they use XInput and WASAPI. SDL2 does no windowing here; each graphics backend makes its own. - FFmpeg (optional, loaded at run time): video decode for cellVdec and ATRAC3plus for cellAtrac. It is never linked and never vendored.
This is a massive undertaking and we need help. Here's how to get involved:
- HLE Module Authors — Fill in the partial modules (media decode, SPURS edge cases) from documented behaviour
- PPU/SPU Experts — Improve the disassembler and lifter accuracy
- Graphics Engineers — Bring Metal and Vulkan to D3D12 parity, then run a title on them
- Game Testers — Try recompiling titles and report what breaks
- Documentation — Help us map out the PS3's system library landscape
See CONTRIBUTING.md for guidelines.
Not sure where to start, or want to sanity-check an idea first? Ask in the Discord — several of the people working on ports and on the lifter are there.
This project does not contain any proprietary Sony code, firmware, encryption keys, or copyrighted material (docs/FIRMWARE_LLE.md explains how LLE works without shipping firmware). It provides clean-room implementations of system library interfaces based on publicly documented behavior. You must provide your own legally obtained PS3 game files.
Contributors are credited in CONTRIBUTORS.md.
MIT License. See LICENSE for details.
155 pull requests, 152 of them from ten contributors, merged in #594. The biggest batch so far, and a different shape from the last few: less of it comes from one port and more of it is platform work that every port gets. D3D12 and Metal both grow a real pipeline cache, raw SPUs run on macOS and Linux, the SPU helpers gain SSE4.1/AVX2 and exact NEON paths, and the diagnostics that had crept into the hot loops are now all behind gates.
RSX and graphics
- D3D12 (@rigaz29, new): indexed triangle
lists are drawn with their own indices (#530); guest depth/stencil state and
samplers are folded into the guest-FP pipelines (#558), with depth surfaces
per zeta offset that are readable as textures and FP depth export (#559).
Guest textures stage through a shared upload ring with least-recently-used
slots (#579), vertices are converted once per draw (#518), and a small batch
can be held back across two flips (#583). The texture-slot SRVs that were
overwriting the SRV heap are gone (#557). New
D3D12_VSYNC=0(#575) and on-demand RenderDoc capture with resources named in guest terms (#561). Duplicate clear-presented flips are skipped, and only those (@Tzeentchnet, new, #486). - Metal (@erikomis unless noted): HLSL→MSL
translations are cached in memory and optionally on disk (#511), a vertex
program's position invariant compiles (#563),
SET_TEXTURE_BORDER_COLORis honoured in the sampler (#476), and the staging arena records into a pooledMTLBuffer(@tekulvw, #440) with one reused buffer for depth readback (#461). - Vulkan: per-target colour mask and blend enable for MRT sets (#516);
VK_DRAW_BATCH=1records engine draws, snapshots, uploads and clears into a single submission (@MaChInEgUn3, #532), with readback staging reused and changed textures refreshed in place (#552). - Draw engine: a scissored
CLEAR_SURFACEclears only the scissor (#560), user clip planes are honoured (#537), and so is the polygon offset (#562). A depth read as a texture converts on the GPU, with eviction from full surface/zeta tables (@n0madic, #499); a depth snapshot is the region the texture names (#507) and a stale one is released (#502). A compressed texture is never a render target's output (#508). A larger surface is reused only on the same sample grid (@tekulvw, #422), each texture key remembers where it was last found (#438), engine-rewritten textures upload without a full hash (#439), the per-draw pipeline key is cheaper (#459), index runs append in one pass (#465), and the depth-to-guest row conversion vectorizes (#460). - Decompilers and vertex fetch: shadow compare is
depth FUNC reference, not the reverse (@n0madic, #424); 3D texel coordinates divide by depth (#482); the vertex program branches on the transform branch bits, with leaders up to slot 544 (#485); WPOS counts pixels on antialiased targets (#446) and follows the RSX's own window convention —SET_SHADER_WINDOWorigin and pixel centres (@MaChInEgUn3, #589). Vertex array addresses wrap at 28 bits (#504), frequency 1 under a modulo divider bit is one element for the whole draw (@n0madic, #547), CMP (11-11-10) attributes decode (@rigaz29, #529), and a draw's vertices are fetched attribute by attribute (@tekulvw, #458).rsx_dispatchemits an immediate vertex for every completing ATTR0 encoding (#463). Linear A8R8G8B8 decodes with one rotation per texel (#432), the depth formats present their one channel on every crossbar source (@n0madic, #501), and the swizzled decode steps the offset instead of re-interleaving each texel (@rigaz29, #578). - GCM FIFO walker (@rigaz29 unless noted): NOP runs are passed over and
3D method runs decoded a command at a time (#554), vertex-program methods
are taken first with one diagnostic gate per FIFO word (#548), the drain's
own ring recycle counts as the JUMP to begin (#553),
GCM_PARK_GRACE_MSbounds how long a park may stand (#531), a park is forgotten once the walker has left it (@erikomis, #541), and a resync replays the label releases it skips (#513). GCM handlers run from blocked semaphore waits on Windows (#576). A flip in the FIFO restoresZSTENCIL_CLEAR_VALUE, and a 0 clear value is the near plane (@n0madic, #526).rsx_stateis handed only the methods with outside effects under the draw engine (@tekulvw, #466), and the EA→IO lookup behind the SPU put hook is bounded (#449).
SPU, SPURS and threads
- Raw SPUs run on macOS and Linux (@erikomis, #473), each with its own
program;
SPU_RunCntl = 0stops a running one (#505), and raw-SPU images can carry a parameter area the loader fills in (#538). - Dispatch and residency (@tekulvw): streamed code regions are verified
once per load and then dispatched by residency (#420), with resident-code
ownership honoured when the interpreter rejoins lifted code (#419) and a
per-thread dispatch cache in front of
spu_lifted_lookup, on by default (#481). The interpreter rejoins inside resident regions (@rigaz29, #525). Indirect-dispatch registry lookups are memoized per thread (#436), as is the per-thread MFC engine lookup (#421), and an image's fingerprint is reused while its bytes are unchanged (#433). - Exact float: NEON float ops without scalar fix-up lanes (@tekulvw,
#445), and opt-in
SPU_FLOAT_RZrunning single precision natively under a round-toward-zero FPCR (#479). SSE4.1 and AVX2 forms of the per-lane integer and quadword helpers (@erikomis, #512), and AVX2 estimates, interpolation and float/int conversions four lanes at a time (@Kurtisone, #500). - DMA, reservations and coherency (@tekulvw):
GETLLARwithout the lock-line lock for registered holders (#441), only the reserved lines of a PUT copied under it (#484), a brief spin before parking on the POSIX lock-line lock (#443), DMA event producers serialized with reservation-lost notifications (#418), a yield before sleeping when a job re-issues the same transfer (#448), the overlay-source scan skipped for small GETs no source can match (#455), and the parked-task scan bounded on every committed lock line (#450).event_statusupdates atomically (@erikomis, #492). - SPURS:
WAIT_SIGNALwakes on coherent guest writes to the signal bitset (#423) and the coordinator wakes when an SPU commits the request line (#478). - Interpreter and lifter: interrupt enable/disable bits are honoured on
every taken indirect branch (#417); pending interrupts are delivered at
merged chunk entries (#435); lifted known-target branches tail-call their
target under
SPU_DIRECT(@erikomis, #510); lifter coverage now verifies job-module regions and embedded SPU programs, reports dispatch misses loudly, and handles spilled PPU jump tables (#444). The drain shares checkpoints and skips calls to inactive guards (#434), resolves its thread-local transfer slot once per drain (#452), and runs the per-hop hooks' common case inline (@rigaz29, #533). Straight quadword load/store sequences run in the SMC microstep on a tight loop (@MaChInEgUn3, #571), and halt andiretlongjmp without unwinding on 64-bit Windows (#572). The decrementer uses the raw monotonic clock on Apple (#451).
Runtime, HLE and syscalls
- New module surface:
cellVoiceResetPort,cellVoiceUpdatePortandcellVoiceGetSignalState(@tekulvw, #487);cellSysconfOpenandcellSysconfAbort(@erikomis, #564); the licence area as system parameter0x0122(@undecuple, #429);cellPadInfoSensorModeandcellPadSetSensorMode(#565);ps3_host_quit, so the window's close button and Cmd+Q reach the guest (#544). - Offline answers:
cellSysutilNpEulaanswers the PSN terms check through its callback (#542), sceNp answers tickets, account region and network time as OFFLINE (#543), and the cellNetCtl net-start dialog ends cancelled (#503). - Threads and sync: a thread that has exited is gone, and its id is not
reused at once (@undecuple, #415); a thread made above its creator's
priority runs until it blocks under
PS3_PRIO_START=1(@n0madic, #416); the main thread's stack information is no longer 0 + 0 (#469); each host thread runs HLE→guest callbacks on a stack of its own (#489);sys_mutexdestroy refuses a mutex that is held or has waiters (#490), andMUTEX_WATCHnames the owner of a lock a thread is stuck on (#474).sysPrxForUserlwmutex moves to an atomic lock word, with a fast path for leaf HLE imports (@rigaz29, #577). The runtime's host threads have names (#567). lv2 syscall 22 is registered as_sys_process_exit(@xuxinsss, new, #587). - Files, audio and media: cellFs repositions the stream when a fd switches
between read and write (@feanor-noldorin,
new, #456);
ppu_fsserializes the fd table and reads each slot once (@tekulvw, #430); cellAudio's WASAPI path keeps 60 ms queued with the mixing thread ahead of the guest (#514); cellVdec drains the decoder when a sequence goes idle with pictures owed (#471) and never hands out handle 0 (@undecuple, #495). stdout and stderr are buffered and flushed on a timer (#524). - cellPad: a controller switched off and on again reopens (#472), XInput
loads at run time rather than being imported (@undecuple, #494), a port
with no controller reports centred sticks rather than zero (@Kurtisone,
#496),
PAD_FILEholds survive empty drain reads (@tekulvw, #570), and an empty XInput slot is polled once a second instead of every frame (@rigaz29, #581). - Clocks and error codes: one host clock backs
mftb, system time and timers, viamach_absolute_timeon macOS (#540). GCM error codes move to base0x80210000and SPURS task codes onto their own0x80410900(@undecuple, #414). - PPU lifter and loader (@rigaz29): guest stores inline, to match the inline loads (#573), on a cheaper access sequence — memory-model copy, one compare, a branch hint (#574); the SPU reserved-line bitmap is tested inline on guest stores (#534); the reservation is re-checked once the lock-line lock is held (#522).
Platforms and build
- macOS: one window survives an
exitspawn, viatools/host_windowand a Metal host-surface mode (@erikomis, #509); the guest runs off the main thread (#477). - POSIX: the project template backs the whole 32-bit guest space, as on Windows (#475).
- Windows: the runtime builds with plain MSVC (
cl), not only clang-cl (@xuxinsss, #588). - CMake: a build configured without
CMAKE_BUILD_TYPEis optimised rather than left at-O0(#506), and the SPU program build can lift with--merge-chunks(@rigaz29, #549).
Diagnostics — all of it now gated
- The hot paths stop reading the environment: the GCM FIFO walker no longer
calls
getenvper packet (@tekulvw, #437),SPU_PCSAMPLEis read once rather than per DMA (@Kurtisone, #243), and the remaining hot debug switches are read once (@rigaz29, #519, #527). - Logs and scans become opt-in: the SPURS module-poll log is capped per process
(#431), the PUT poison scan runs only when it can be reported (#454), the
closed policy-module DMA trace counter stops advancing (#453), two per-event
log lines in cellVdec and
spu_channelsare opt-in (@rigaz29, #521), and the guest load/store watch hooks are gated behind one inlined load (@tekulvw, #483). - New samplers and reports:
PS3_TPROFfor SPU and PPU threads (#480),RSX_WALKER_PROFfor the FIFO walker thread (#467),SPU_IRQWAIT_DIAGfor an SPU waiting on an interrupt that never comes (@erikomis, #491),SPU_INTERP_STATSnow listing where the interpreter was entered (@rigaz29, #523),PS3_SAMPLE_DRAIN=1to sample only the RSX drain thread (#520) with exact attribution underPS3_SAMPLE_RVASand a one-thread fast path (#568), and an ftrace span per HLE import call with its own report section (#580).
Tooling and docs
lift_jobmodslifts each job module at the link base its header names (@erikomis, #488);ppu_lifter --insn-patcheslifts patched instructions as run-time switches (#539); the twistedmetal regression run removes its FIOS file cache first (@Kurtisone, #498).- Docs (@undecuple):
SPU_LIFTER.mdrefreshed (#425), the SPU workflow added toGETTING_STARTEDand the porting guide's Phase 11 (#426), prerequisites made to agree across README,GETTING_STARTED,BUILDING,TOOLSand the porting guide (#427), and template paths made to match the CMake withconfig.tomlmarked reference-only (#428).CITATION.cffadded (#535).
Housekeeping
- The five third-party GitHub Actions are pinned to commit SHAs (#590), the
release.ymlwrite token is scoped to the job that publishes rather than held by the job that compiles the tree and runs every test script (#592), and.github/CODEOWNERSrecords the paths that execute (#593). CMakeLists.txtsaidVERSION 0.11.0, six releases stale, so every configure printedps3recomp runtime v0.11.0. It says0.18.0now.runtime/spu/tests/test_spu_int_neon.candtest_spu_float_neon.crun on the macOS arm64 job. The integer one had never been compiled by any workflow on any platform; neither had been built for NEON on an arm64 host.
Known issue
- You Don't Know Jack can hang at boot in a SPURS
EventFlagWaitthat no workload ever sets. The race is on v0.17.0 too (1 run in 4), but this release hits it far more often (4 in 4 on the regression gate). It climbs across several merges rather than coming from one PR, and is being chased separately.
33 pull requests from seven contributors, merged in #413. Most of them come from two new God of War ports (HD and Ascension), plus Killzone 3, Twisted Metal and SoulCalibur II HD.
RSX and graphics
- God of War HD on D3D12 (@rigaz29, new):
depth/stencil-only clears no longer wipe the scene (#393). Indexed strips
keep their winding (#391). The guest-FP pipeline cache is keyed on the code,
not the address, which removed a full recompile per draw for programs
uploaded to a ring (#392). The FP decompiler is told the draw's export width
(#396). A wrapped command ring no longer overwrites commands the RSX hasn't
read (#390).
initguid.his included in the right place (#389), and newFP_DUMP=<n>(#398),PS3_HLE_TOP=<s>(#397) andSPU_INTERP_STATS=<s>(#394) diagnostics. - God of War: Ascension (@MaChInEgUn3, new): X16 textures present like B8, so the font atlas shows (#384). A smaller clip on the same rows reuses the surface (#382). The Vulkan pipeline table is as large as the engine's (#378).
- Killzone 3 (@undecuple): texture offsets
are 31 bits (#408). A texture smaller than the surface it aliases samples
the surface's top-left (#395).
getis published past a semaphore RELEASE before its label (#401). Main-memory maps take the first free IO pages, and are refused beforecellGcmInit(#410).
SPU, SPURS and threads
- The Twisted Metal bring-up runtime is on master, so that port links again (@Kurtisone, #381).
- Taskset bitsets are updated atomically on task create and exit (#388).
cellSpursQueueSizeis answered (#411), and non-joinable PPU threads free their slot when they end (#409) (@undecuple). - The identical-transfer DMA halt also waits for wall time and backs off, so a job polling an RSX label isn't killed (@MaChInEgUn3, #383).
cellFiberis the SDK's scheduler API, replacing the made-up one (@n0madic, #400, closes #365).
Memory, codecs and system
- LV2 user allocations and mapper reservations are separate domains, and loaded ELF segments are never handed out (@tekulvw, #296).
- cellVdec:
QueryAttrEx/OpenEx(#379), and time stamps and frame rate for MPEG-2 pictures (#380). WASAPI shared mode converts the 48 kHz stream, so a 44.1 kHz or 5.1 device isn't silent (#385) (@MaChInEgUn3). - Log caps stop at their limit (
PS3_LOG_FIRST) instead of wrapping and printing on every call (@n0madic, #399, closes #364). MinGW builds the tests and reads the time zone from the system (#402). - Lifter: jump-table bounds compares are found beyond the 30-instruction
window (@undecuple, #387).
lift_jobmods --merge-chunksis passed through (#386). - The project template maps the guest arena with
mmapon POSIX, sovm_commitcanmprotectit (@arnaudaprahamian, new, #412). - Docs: stale module counts removed (#405), Killzone 3 entry updated (#407).
44 pull requests from six contributors, merged in #377. They come from inFAMOUS 2, Twisted Metal and SoulCalibur II HD, plus Tornado Outbreak.
RSX and graphics
- 3D textures in the draw engine (@erikomis, #335).
The fragment decompiler also gains FACING, TC8 and TC9 (#328), the
perspective-correct flag on texcoord reads (#329), and signed results from
biased-remap and
_bx2fetches (#331). Y16_X16/HILO8 crossbars present R-G-R-G (#332). - A flip in the command stream completes when the RSX reaches it
(@Kurtisone, #343), and a late flip
completion no longer marks a newer flip done (@erikomis, #354). Also:
get follows the walker across a JUMP (#347), the semaphore acquire is
bounded (#327), and GCM callbacks are delivered at
sys_timer_usleep/sleep(#353). - NV3089: the source origin is 12.4 fixed point, and copies were 256 times too short (@n0madic, #358). Unscaled blits copy a row at a time (#334). 2D transfers read FP16 targets (#367) and convert a pixel at a time (#348).
- Speed: the D3D12 vertex program cache is keyed on the program instead of the store behind it, which took most of the D3DCompile calls off the FIFO thread (@n0madic, #361). HLSL to SPIR-V translations are cached (#346), cached textures are re-hashed sparsely (#375), and the per-vertex span is found once per draw (#357).
- Vulkan: colour feedback snapshots for draws that sample their own target (#352), and present on its own command buffer (#351).
- Metal: per-MRT colour mask and blend (#330),
PS3_ANISO(#373),PS3_AA=fxaaandPS3_SHARPEN(#374),cellVideoOutSetGamma(#355), andprecise::math from spirv-cross (#356). - Diagnostics:
PS3_FTRACE, a frame timeline of who waits for whom (#339), and fragment-program debug knobs keyed by structural hash (#336).
SPU and SPURS
- An SPU thread starts in the lifted image its own bytes identify, instead of whichever image registered first at that entry point (@n0madic, #362). An SPU user event finds the port the PPU binds, and waits for it (#363).
- A task's signalled bit is updated atomically against SPU commits (#340), and a job's first frame stays below its cache buffers (#366) (@Kurtisone).
- Single-precision fast paths run four lanes at a time with AVX2 (#369) and SSE2 (#370).
- Syscall 14 classifies lock-line addresses by guest segment (@kalpakprod, #341).
System libraries
- cellFs: the
CELL_FS_O_*flag values are corrected, soO_CREATcreates (@kalpakprod, #349);/dev_hdd1maps to a writable host root (#350); and an AIO read keeps the fd's position (@Kurtisone, #376). cellGameBootCheckreports the game type from PARAM.SFO (#359), andCELL_MSGDIALOG_BUTTON_NONE/INVALIDare no longer swapped (#360) (@n0madic). An HDD title's/dev_hdd0/game/<id>/now resolves to the booted game tree, which kept Simpsons Arcade reading its data once #359 reported it as an HDD game.PS3_LANGpicks the system language (#333), andPS3_GAMEDATA_ROOTmoves saves and trophies out of the working directory (#338). The small rumble motor runs at full strength (#372) (@erikomis).- Guest spinlocks use a 32-bit atomic on LP64 hosts, which fixes a fault on arm64 (@tekulvw, #326).
- Tornado Outbreak: the 2x zoomed frames from #281 are fixed (#344).
Older releases: CHANGELOG.md.

