jpolo1224 0bfefd4b69 LSFG: run frame generation on our own device, and delete the old path
Completes the switch to the Eden port. GSLsfg keeps its entire public surface —
availability, status text, display FPS, the settings and OSD plumbing all
untouched — and only its internals change, so nothing above the renderer had to
move.

What actually changed on screen: the old implementation ran the interpolator on
a SECOND VkDevice and shared images as AHardwareBuffers, and because Android
offers no cross-device semaphore (Turnip rejects OPAQUE_FD export on AHB memory)
the only barrier available was a full device idle — twice per frame, every
frame. That is gone. Generation is now ordinary compute recorded into a command
buffer on the device we already have, and interpolated frames are written
STRAIGHT into an acquired swap chain image through a storage view, so the
intermediate copy is gone too.

The pacer comes with it, which is the fix for games that oscillate between 60
and 30fps on a 60Hz panel: the generation count now varies to hold the presented
rate near a target instead of blindly multiplying whatever the game produced.

★ ONE submit, N+1 semaphores. All the generation work goes into a single
command buffer, submitted once, waiting on the caller's render-finished
semaphore plus every acquire, and signalling one semaphore per present that
follows. The obvious alternative — a submit per generated frame — walks straight
back into the binary-semaphore bug this file was bitten by before, where the
real present and the first generated present both want to wait on the semaphore
that says the source has been read. A binary semaphore may be waited exactly
once.

★ The hook fires AFTER vkQueueSubmit, so FrameGen had to take its command
buffer as a parameter. It was written against GSDeviceVK::GetCurrentCommandBuffer(),
which at that point is in flight or already belongs to the next frame; recording
into it is undefined and the symptom would have been interpolation running a
frame late rather than anything resembling an error.

Layout bracketing is ours: the ported passes speak Eden's convention where a
presentable image lives in GENERAL, and PCSX2 hands them over in PRESENT_SRC_KHR
and needs them back in it.

The swap chain now requests VK_IMAGE_USAGE_STORAGE_BIT — but only when frame
generation is on AND both the surface and the chosen format allow it. Asking
unconditionally fails swap chain creation outright on drivers that do not, which
would take the whole renderer down for a feature that is switched off. The
format half is the easy one to miss: a surface can report STORAGE support while
the sRGB format picked for it has no STORAGE_IMAGE feature bit, and that only
shows up later as a validation error at image-view creation. Because usage is
fixed at creation, switching the feature on mid-session needs a renderer
restart; Initialize says so rather than failing silently.

DELETED: platforms/android/app/src/main/cpp/3rdparty/lsfg in full — the
lsfg-vk-android framegen library, the DXVK dxbc compiler, pe-parse, volk and its
759-symbol collision with VKLoader, the C ABI shim, the version script, the
separate .so and the dlopen that found it, and the -fexceptions carve-out they
needed. GSLsfg.cpp went from 1259 lines to 654. The ~130 MB configure-time fetch
goes with it.

build-play-aab.sh's guard was rewritten rather than dropped: it checked for a
file that can no longer exist either way, so it would have passed forever
without proving anything. It now looks inside the core for a symbol only the
ported implementation defines.

Verified: all 18 affected translation units compile without errors, with
ARMSX2_HAS_LSFG on AND off (the play flavour still compiles the feature out
entirely). Not yet run on hardware.
2026-08-21 01:14:30 -04:00
2026-07-27 19:48:36 +02:00
2026-04-03 12:41:47 -04:00
2026-07-18 12:04:18 -04:00

ARMSX2 — Native ARM64 JIT Fork of PCSX2

All Platforms

ARMSX2 is a free and open-source PlayStation 2 (PS2) emulator based on PCSX2. Its purpose is to emulate the PS2's hardware, using a combination of MIPS CPU Interpreters, Recompilers and a Virtual Machine which manages hardware states and PS2 system memory. This allows you to play PS2 games on your phone, PC, or gaming handheld, with many additional features and benefits.

Thank You

The ARMSX2 team is eternally indebted to the PCSX2 project it is based on. We are so fortunate to build on their 20 years of hardcore development.

About This Fork

Project Demo

The upstream PCSX2 project ships an ARM64 interpreter build for ARM, but its high-performance JIT recompilers (EE, IOP, VU0, VU1, and vtlb fast memory) are x86-64 only.

This fork exists to close that gap. The goal is to preserve the correctness features of 20 years of PCSX2 development, while generating the fastest native ARM performance possible.

Current status:

  • EE (Emotion Engine) recompiler — integer, float, MMI, COP0/COP1/COP2, branches, load/store
  • IOP (I/O Processor / R3000A) recompiler — full integer, load/store, branches, coprocessors
  • VU (Vector Unit) recompiler — microVU skeleton + Upper FMAC vector ISA complete; Lower ISA and runtime complete
  • vtlb fast memory
  • Native ARM64 binary builds and boots the PS2 BIOS
  • 2D games are already playable
  • 3D games run

Why LLMs / AI Were Used

A word on methodology:

The x86-64 JIT code in upstream ARMSX2 is already proven correct — it has run thousands of PS2 titles for years. The challenge in this port is not emulator design or JIT theory; it is mechanical translation of a large, well-understood x86-64 assembly codebase into equivalent ARM64 assembly (via VIXL) while preserving the exact same register-allocation contracts, block lifecycle, and recompiler semantics.

Large language models (LLMs) were used as an accelerant for this translation work — pattern-matching x86 JIT boilerplate to ARM64 equivalents, scaffolding emit routines, and keeping the porting velocity high. The JIT logic (block compiler, dispatcher, analysis passes, flag pipelines, clamping rules, Tri-Ace hacks, etc.) is taken directly from the upstream x86 implementation and validated against it. Nothing was hallucinated from scratch.

In other words: the hard engineering was done by the PCSX2 team over two decades. The hard typing — translating ~50k lines of x86 emitter code into ARM64 — is what AI helped compress.

System Requirements

ARMSX2 targets ARM64 across desktop (macOS, Windows, Linux) and mobile (Android, iOS/iPadOS), all from the single shared core. Our setup documentation page contains additional details on software and hardware requirements.

Please note that a BIOS dump from a legitimately-owned PS2 console is required to use the emulator. For more information, visit this page.

Building

Check out our github actions for the latest build recipe

S
Description
No description provided
Readme
512 MiB
Languages
C++ 68.2%
Kotlin 9.8%
Swift 7.7%
C 5.6%
Objective-C++ 2.2%
Other 6.4%