Crash and correctness
- Fix a crash when backgrounding the app mid-game: onPause flushed the Vulkan
pipeline cache from the UI thread while the GS thread was creating pipelines
into the same VkPipelineCache. Vulkan requires that handle to be externally
synchronised, so this was a driver-level data race and crashed on Adreno and
Xclipse alike. The flush now runs on the GS thread, posted via the CPU thread
so it does not race the EE-owned MTGS ring.
- Fix an unbounded out-of-bounds vertex read in the GSRendererHW sprite-merge
paving path: the inner loop advanced i instead of j, so j stayed loop-invariant
and the scan walked past m_vertex->tail.
- Fix per-game settings being silently ignored: gamesettings/<serial>_<CRC>.ini
loads into a higher-priority layer than anything the app writes, and saves made
from the library never regenerated it, so any key already in that file
overrode the user permanently. Only the category-Reset path rewrote it, which
is why Reset appeared to be the only thing that worked.
- Fix screen rotation: the BIOS followed the launcher rotation instead of the
renderer's (it has no GameInfo, and the tier was keyed on that), and the
launcher stayed locked in a game's orientation after exit because the cleanup
lived only inside stop()'s vmRunLoopActive-guarded branch, which loses a race
against the VM thread's own finally. Rotation tier is now an explicit flag and
the cleanup runs on every terminal path.
- Discard the Vulkan pipeline blob whenever the SPIR-V cache is discarded. It was
validated only against the device header (vendor/device/pipelineCacheUUID),
which is identical across an app update, so a SHADER_CACHE_VERSION bump kept
every pipeline built from the old shaders and nothing pruned it.
- Make eeRecExitRequested atomic: it was a plain bool written from the JNI thread
and read on the CPU thread.
- OpenGL: restore GL_PACK_ALIGNMENT after readback, add the missing memory
barrier after the CAS dispatch, and initialise GLState::depth_mask to GL's
actual default.
- DEV9: log the GetNetAdapter default: bail and the InitNet skip. Both returned
silently, so a settings mistake surfaced as missing hardware three layers away.
Local Link (new)
- New DEV9 backend bridging emulated PS2 Ethernet between devices over
authenticated local UDP, so games with a built-in LAN / System Link mode can
play together. Ported from EmuCoreX (sashkinbro) with the wire format
unchanged, so peers remain compatible across both forks.
- Network mode picker (Online / Host / Join), host address readout, auto-derived
peer ids, generated room codes, hostname support alongside numeric IPv4, and a
link to the supported-games list. Fully controller-navigable.
Performance
- Asynchronous hardware download mode (experimental, opt-in): non-blocking
GPU->CPU readback so the EE thread no longer waits on the GS thread. Ported
from EmuCoreX. Appending Asynchronous to GSHardwareDownloadMode makes the enum
non-ordered, so the relational comparisons on it are replaced with
IsHardwareDownloadReadbackEnabled / IsHardwareDownloadEEThreadRead.
- Affinity Control Mode (experimental, opt-in): EE/VU/GS priority orders plus a
Performance Cores mode. Android otherwise leaves these threads unpinned.
- Raise the texture-replacement cache ceiling from 6 to 16 GB; RAM/2 remains the
real limiter, so this only binds at 12 GB RAM and up.
- Low Latency frame pacing is no longer the default, with a one-time migration
for installs that took the earlier flip.
Features
- Auto renderer resolves to Vulkan HW on Adreno.
- Auto Progressive Scan (per-game): holds Triangle+Cross through boot.
- OLED black as a modifier over any accent colour, including Custom and RGB.
- Optional system keyboard instead of the built-in on-screen one.
Game compatibility
- Everybody's Golf 4 / Hot Shots Golf Fore! hwDownloadMode across all regions
(PR #421, XDarkFallenX).
- Delta Force: Black Hawk Down (PR #401, XDarkFallenX).
- Reduced input latency and input handling improvements (PR #403, Splaser).
RetroAchievements
- Inject the client version from a build-time secret kept out of public source,
with a stock-PCSX2 fallback for secret-less builds, so third parties cannot
copy the client identity. Covers the iOS token too.
Android's Auto DNS returned an empty list before 2.6.4; 2.6.4 started falling
back to public resolvers (1.1.1.1 / 8.8.8.8), which the console reaches over a
real UDP round-trip through the sockets forward path. Fast-forward outruns that
round-trip's wall-clock timing and DNS fails (#379). Restore the pre-2.6.4
behaviour by leaving Android out of the public-resolver fallback; iOS is
unchanged, and the separate GetAdapterAuto gateway-probe skip stays.
The mobile fallbacks were gated on TARGET_OS_IPHONE only. On Android
GetAdapterAuto still required a host default gateway, which the app
sandbox cannot read out of /proc/net/route, so auto-selection failed and
InitNet force-disabled Ethernet for the session - reported as
"connection device not found" with the interface plainly visible in the
picker. GetDNS likewise returned an empty list because there is no
/etc/resolv.conf.
Extend both gates to __ANDROID__: select on a usable IPv4 interface and
fall back to public resolvers. iOS and desktop behaviour is unchanged.
The ios/pr-ready merge (04ea993e99) introduced two independent
regressions in the shared core:
1. DEV9/AdapterUtils.cpp included Apple-only <TargetConditionals.h>
unconditionally under __POSIX__, so every non-Apple POSIX target
(Linux, Android, FreeBSD) failed to compile. Guard the include with
__APPLE__; TARGET_OS_IPHONE is only consulted to keep iOS out of the
BSD-socket block, and on non-Apple it correctly evaluates to 0.
2. SPU2::RegisterNEONBackend() is called from spu2.cpp on every arm64
target (guarded by __aarch64__ / _M_ARM64), but spu2_neon.cpp was
only added to the build for Android/iOS -- so desktop arm64
(macOS/Linux/Windows) failed to link with an undefined symbol.
Compile spu2_neon.cpp on all ARCH_ARM64 targets. The NEON reverb
backend stays opt-in (SPU2/NeonReverbSIMD, default off).
While wiring it up for desktop:
- Drop the unused spu2_neon_mixer/_reverb_ex/_dcfilter includes from
spu2_neon.cpp. They hold helpers for a mixer.cpp/ReaVerb.cpp
integration that hasn't happened, and use the MSVC-only
__forceinline keyword unguarded (breaks clang). The TU only needs
the reverb FIR plus the SVE2 hook.
- Guard spu2_optimize.h's x86-only <xmmintrin.h>/_mm_prefetch off
MSVC-on-ARM64 (falls back to the no-op prefetch).
Verified locally: clean Release build + link on Linux arm64
(RegisterNEONBackend now defined in the binary).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Gate all macOS-only system APIs behind TARGET_OS_IPHONE checks across the shared core: ApplicationServices, IOKit, mouse APIs, AppKit, MetalFX, CDVD Darwin sources, USB, discord-rpc, cubeb CoreAudio HAL, and BSD networking headers in DEV9. Port TARGET_OS_IPHONE guards for DEV9 AdapterUtils with iOS fallbacks for sockaddr_dl, rt_msghdr, and sysctl. Add ARMSX2_ROOT to the include path for the frontend's common include style. Drop the global _M_ARM64 define that triggered fast_float MSVC intrin.h inclusion since __aarch64__ covers the core paths. Gate MTLFeatureSet_macOS_GPUFamily1_v1 behind !TARGET_OS_IPHONE. Fix missing unistd.h and gate pthread_jit_write_protect_np which is unavailable on iOS. Add stubs for DarwinMisc JIT diagnostics, Achievements stats and info APIs, Discord_Register, Host capture callbacks, and the host hotkeys map so the frontend links cleanly. Merge upstream master.