Merges yaps2/main (github.com/yaps2/yaps2, c16b88cb7) into ARMSX2,
replacing the arm64 recompiler family with the yaps2 JITs and importing
the yaps2 testing, perf, and libretro infrastructure. Common ancestor is
upstream PCSX2 342db5152 (2026-06-19); git auto-merged all but 38 files.
Replaced (deleted in this merge, recoverable from history):
- arm64/aR5900*, aR3000A*, aVU* -> arm64/iR5900*/iR3000A*/microVU*-arm64:
EE static-pin register file with lazy dirty tracking, dual-residence
allocator, IOP block linking, native COP2 macro ops, inline unaligned
fastmem, persisted VU program cache, call-ret shadow ring, VU0 spin
fast-forward.
- MVU_DIFF shadow-run hooks in shared VU interpreter TUs (superseded by
the offline vurunner JIT-vs-interp oracle).
Imported from yaps2:
- tests/ctest/core/recompilers: ~80 gtest suites (EE/IOP/VU differential
harnesses, fuzzers, ABI digest tripwire, capture format pins) plus the
gs_vertex_tests kernel oracle.
- pcsx2-vurunner / pcsx2-eerunner headless capture-replay runners.
- tools/perf counter-based A/B rigs, perf jitdump productionization,
PmuCounters, clang-perf/clang-handheld presets.
- pcsx2-libretro core (ENABLE_LIBRETRO, default OFF; rename pending).
- GS vertex-kick fast path (GV series): TBL-based packed parse,
register-resident kick, scalar-outcode cull, fused draw-rect/FindMinMax.
- Null renderer, VK_KHR_display direct WSI, swapchain PresentStats.
- SPU2 NEON mixer vectorization, EE timer read clamp (NFL 2K5 hang),
IOP ioman signed-compare fix, assorted UB fixes.
Kept from ARMSX2 in the both-touched files:
- iOS dual-map W^X and fastmem-unavailable resilience (Memory, HostSys,
vtlb). The split data/code area model is retained; both areas now take
fixed VA hints so cached VU JIT code stays deterministic on Linux.
- Android thread-affinity model, VMState shutdown early-outs, all
platform frontends, branding, CI, RetroAchievements identity/policy.
- GSDeviceVK: ARMSX2's push-descriptor decision logic (Mali crash gate,
proprietary-vs-turnip Adreno split) merged with yaps2's descriptor-pool
exhaustion recovery (flush + render-pass restart instead of dropped
binds). Vendor feature policy is the union: Mali fbfetch policy with
MediaTek/G57/Xclipse gates from ARMSX2; Adreno stencil/ROV/
test-and-sample-depth hang avoidance and no_ps2_z_quantization from
yaps2.
Build-system notes:
- The Qt debugger is now gated behind ENABLE_QT_DEBUGGER (default off on
arm64) so handheld builds drop the KDDockWidgets dependency.
- GSDeviceNone and remaining yaps2 GS code were ported to the newer
upstream GSTexture Usage-flags API.
The replaced backend's interpreter-fallback glue (intExecuteOneInst,
AndroidEEOpHist) and the EEDiffVerify runtime differ are retained for
now; dead pieces will be removed in a follow-up commit.
OSD now hides via RenderOverlays mirror of EmuConfig.GS->GSConfig + seed-false on first launch. Rumble: forward SetPadVibrationIntensity to Native::onPadRumble on Android (mono core had no call site). Library: bundled PS3 XMB-wave MP4 as default background, drawn edge-to-edge via ArmsBackdrop backgroundLayer (fixes landscape strip). In-app on-screen keyboard for library search; Recently Played shelf selection highlight; settings category tabs reachable via Row+horizontalScroll. Persian (fa) translation; gold RetroAchievements trophy.
An SD865 profile of SotC (locked 60, Release, MTVU) shows
__kernel_clock_gettime at 4.1% of the EE thread - the largest non-JIT
symbol. GetCPUTicks() went through the vDSO (function call + seqlock +
isb + ns conversion) on every read, and the framelimiter's
frame-boundary spin in VMManager::Internal::Throttle() calls it tens of
thousands of times per frame.
Read the architected virtual counter directly instead: CNTVCT_EL0 ticks
at CNTFRQ_EL0 (19.2MHz on SD865, 24MHz on Apple M2), is monotonic and
consistent across cores, and is exactly what the vDSO reads underneath.
Measured 1.24ns vs 13.39ns per call (10.8x) on M2/Asahi.
GetTickFrequency() now returns CNTFRQ_EL0 so every freq-relative
consumer is unaffected. Resolution drops from 1ns to ~52ns, ample for
frame pacing and the sub-ms throttle spin. This mirrors a bare-mrs
pattern used elsewhere for GS counters.
Caller audit for the tick-unit change (only one thing assumed
nanoseconds):
- VMManager::Throttle, GSDumpReplayer, GSDevice present throttle,
PerformanceMetrics, HostSys spin calibration: all convert through
GetTickFrequency() - unaffected. (HostSys's "time > 100" calibration
threshold now means 100 counter ticks, ~5.2us; the doubling loop just
runs slightly longer.)
- Threading::SleepUntil (Linux) built an absolute CLOCK_MONOTONIC
timespec directly from the tick value, which breaks with raw counter
ticks (different epoch). Rewritten as a relative sleep off the
remaining delta with an early-wakeup retry loop, matching the
Windows/Darwin implementations.
- common/Perf.cpp jitdump timestamps use their own clock_gettime and
must stay in perf's clock domain - untouched.
- Common::Timer is a separate clock domain, never mixed with
GetCPUTicks values - untouched.
- GSRendererSW/GSFunctionMap LOG-gated dev stats print raw ticks -
compile-time disabled dev code, freq-relative where it matters.
x86 Linux and Darwin (already on mach_absolute_time) are unchanged.
Validated: recompiler_tests 1083/1083 green; standalone check on
M2/Asahi shows 0 monotonicity violations over 10M reads, 0.0002% error
vs CLOCK_MONOTONIC over 500ms, SleepUntil overshoot ~60us (normal
nanosleep wakeup latency) and instant return for past targets.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CMake/preset wiring for the ARM64 target, the vixl C++20 enum-conversion warning
suppression, PmuCounters (cycle/instret PMU reads), and the Perf jitdump dir/enable
controls (EmuConfig.Profiler.EnablePerfDump, redirected out of /tmp into the cache
dir). Plus small platform/build fixes (ALSA thread naming, SmallString, X11 guards,
ARM MIDR CPU-name fallback, gcc lambda decay). The ARCH_ARM64 status banner now
reflects that EE/IOP/VU recompilers are all implemented.
Co-Authored-By: Ryan Walklin <ryan@testtoast.com>
Co-Authored-By: Brian Degenhardt <bmd@bmdhacks.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
All games use mailbox/triple buffering. Except when you enable sync to
host refresh, in which case FIFO/double buffering is used.
This means vsync enabled will ever tear, but at the same time, never
drop to 30fps on a missed frame due to frame rate differences.
To have the "best of both worlds", you should enable vsync and sync to
host refresh. Previously, this resulted in additional input lag, since
the host vsync would drive the EE frame timing. Now, this behaviour is
disabled by default, unless you enable "Use Host VSync Timing".