mirror of
https://github.com/ARMSX2/ARMSX2.git
synced 2026-08-24 16:50:16 -07:00
master
1743
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
a6d1e35748 |
Settings: copying global settings into a game writes only the real decisions
"Copy Global Settings" does not copy the settings you can see. It runs the whole configuration through a wrapper that writes every key unconditionally, so the file it leaves behind holds roughly seven hundred of them — network adapters, the debugger, trace logging, memory cards, sections no settings page ever shows. That was untidy and no worse, until a key present in a per-game file started meaning the player claimed it. Now one press of a button whose dialog promises only that "the configuration for this game will be replaced by the current global settings" turns off every automatic fix that game had, permanently and silently. A value is worth writing down only if it decides something, and there are two ways it can fail to. It can be the stock default, in which case the file carries it as noise. Or it can be what the game database is going to set anyway, in which case writing it can only become a claim that suppresses the fix it agrees with. So the copy now excludes both, and what lands is what the player actually chose. The comparison goes through the string form rather than the typed value, so a float or an enum name compares the way it will be stored rather than the way it happens to sit in memory. That is why the references are built with the same interface class: same formatting on both sides, exact comparison, one path for every type. The database reference is a default configuration with the entry applied, not this one with the entry applied. The question is what the database wants, not where it would leave the source. It matters for the handful of fixes that clamp rather than assign, and it errs towards writing the player's value — never towards dropping a fix, since a value is only skipped when it already equals what the fix would set. Working the reference out means running the apply functions for an outcome nobody is going to run with, so they take an apply mode. A hypothetical apply says nothing to the log, raises none of the recommendation messages, and does not allocate the four megabyte lookup table that the Goemon TLB fix asks for. The tests cover the precedence rule and the filter, but the ones that matter are the drift guards: they assert every gamefix, speedhack and clamp mode has a settings key, and that the only graphics fixes without one are the six that genuinely have no setting behind them — three renderer routine selectors and three that only raise a recommendation. A knob nobody maps is a setting that goes quietly back to being overridden, with no warning and no failure, and that is what these are here to catch. |
||
|
|
a3bf73bf7a |
GS: AArch64 has no slow unaligned load to compile around
FAST_UNALIGNED was defined only inside the ARCH_X86 arm, where it records that AVX-and-later cores stopped punishing unaligned vector loads. On ARM64 the macro was therefore undefined, which the preprocessor reads as zero, so every arm64 build compiled the texture-upload path as though the punishment existed. It never did. LDR Q and LD1 take any address, and GSVector4i's load template ignores its own `aligned` parameter and emits the same instruction either way. So the callers were paying for a distinction with no machine behind it: WriteImage tests the source address and the pitch on every call to choose between three template instantiations of WriteImageBlock and WriteImageColumn that, for 8- and 4-bit columns, compile to identical code. For 32- and 16-bit columns the unaligned arm is not identical, but it is the worse one — eight combining 64-bit loads instead of four 128-bit loads and a swizzle. Defining it collapses all of that. GSLocalMemoryMultiISA.cpp.o goes from 80,368 to 62,184 bytes of .text and from 58 emitted functions to 32, which is what an I-cache on a handheld cares about. Only GSBlock.h and GSLocalMemoryMultiISA.cpp read the macro, so nothing else moves. The retained load strategy is not new code: whenever an upload happened to land 32-byte aligned, arm64 already ran exactly this sequence. What goes away is the arm that only ever ran when it did not. |
||
|
|
5b2713c220 |
Comments: stop calling a CPU tick a microsecond
Both comments predate GetCPUTicks() reading CNTVCT_EL0 and give a tick scale this host does not have; one of them leaves a plain tick count looking like a duration. The code under them already divides by GetTickFrequency(), and is unchanged. |
||
|
|
2e39fcc216 |
Optimization: wait on the address instead of spinning the pipeline
Each of the three spin-then-sleep semaphore loops watches a single atomic word, but ShortSpin() has no way to know that: it spends its share of SPIN_TIME_NS in batches of eight isb, and every one of those is a pipeline flush. arm64 can watch the word itself, so ShortSpinOn() does, and the loops that hold their whole predicate in one word take it. Hosts that cannot watch an address keep the old spin. Inspired by Whatcookie's work on arm64 for rpcs3. |
||
|
|
00ee8185b8 |
iOS: read JIT activity under the validation lock
Follow-up to the keepalive work in the hybrid JIT safety change. The lock it adds closes the race between the idle canary and code memory being unmapped, which is the important half, but the activity check sits outside that lock and leaves a smaller gap behind. WaitForJITValidation drains by taking the mutex and dropping it again, so it only ever waits for a handler that has already acquired the lock. A handler that passed the activity check but has not reached the acquire yet is invisible to it. The boot path sets the VM active, cancels the timer and drains, all of which that handler misses, and then it carries on into BeginCodeWrite and flips protection across the whole arena while the EE thread is executing out of it. That is the same shape as the Devil May Cry crash, and the comment above ARMSX2JITWorkerBusy already describes the consequence as an instant instruction abort. Reading activity inside the lock leaves only two possible orderings and both are fine. Either the handler gets there first and the drain waits for it to restore the canary byte, or it gets there second, sees the VM is busy and returns without touching anything. The window is a few instructions against a twelve second timer, so nobody was going to hit this on purpose, but it costs two lines to remove. |
||
|
|
45368481be |
iOS Hybrid JIT Safety, No-JIT Fallback, and Interpreter Performance
# iOS Hybrid JIT Safety, No-JIT Fallback, and Interpreter Performance ## Summary This pull request preserves the current master JIT path while making iOS game boot reliable when JIT is unavailable, revoked, or unable to allocate executable code memory. Instead of continuing into recompiler-only code with missing mappings, ARMSX2 selects the existing interpreter providers and disables only the facilities which require generated native code. It also adds a conservative predecoded EE interpreter block cache and enables link-time optimization for the iOS PCSX2 core. Together, these changes improve the practical No-JIT path without changing the normal JIT execution architecture. Base revision after fetching the latest master: `1a5fc1c3731dd98f84eb62c7d9ac948241743ce7` The working branch and `origin/master` were already identical at that revision, so no commit replay or conflict resolution was required. ## Problems addressed ### Booting without JIT could crash or remain on a black screen The emulator previously continued through code paths which assumed executable code memory existed. If iOS had not granted JIT, had revoked it, or the executable mapping could not be allocated, null or unavailable code-cache memory could still reach: - The EE and IOP recompilers. - microVU0 and microVU1. - Generated VIF unpackers. - The software GS scanline JIT. - Fastmem setup. - MTVU paths which depend on generated VIF execution. The new capability-driven fallback allows the VM to start using existing interpreter implementations instead of invoking those incompatible providers. ## Performance impact ### No-JIT EE execution The user-observed EE time changed from **37.55 ms to 30.55 ms** after the conservative cache and ThinLTO baseline was introduced. That is: - **7.00 ms less EE time** in the observed workload. - Approximately **18.6% lower EE processing time** for that workload. - Approximately **1.23x the previous EE throughput**, if all other conditions are equal. This is an observed device result supplied with the change, not a benchmark performed during this packaging step. Results remain game-, scene-, device-, thermal-, and settings-dependent. The fixed block cache uses approximately 1 MiB of static memory on 64-bit builds. It trades that bounded allocation and per-block RAM validation for fewer repeated instruction decodes. ### Normal JIT gameplay The EE block cache is not called from the JIT's `recExecute()` path. No cache lookup, validation, or interpreter callback is added per JIT-generated instruction. The validation mutex is used only during idle JIT checking, startup transitions, backend switching, and teardown. The keep-alive timer is stopped before gameplay. ThinLTO may provide a small native-core improvement, but no specific steady-state JIT gain is claimed. ### JIT validation could race code-memory teardown Master's JIT keep-alive validates more than the `CS_DEBUGGED` process flag: it checks the active writable code mapping by writing a temporary canary byte, reading it back, and restoring the original byte. That stronger validation is retained. The problem addressed here is synchronization: canceling a dispatch source prevents future callbacks but does not wait for a callback which is already executing. Without a shared lifetime boundary, a callback could retain the mapping address while another path dismantled the code cache. ### Persistent workers cannot safely change backend in place A JIT worker owns executable mappings and initialized recompiler providers. An interpreter worker deliberately owns neither. Reusing one worker as the other backend can leave incompatible memory and provider state. Backend changes now perform a complete worker teardown and recreation rather than attempting to mutate an initialized worker. ### The instruction-by-instruction EE interpreter repeated decode work No-JIT EE execution previously fetched and decoded every instruction every time it executed. Repeated loops therefore paid the same opcode lookup cost continuously. A bounded block cache now stores short, validated sequences of instruction words and their predecoded opcode descriptors. ## JIT behavior preserved from master The normal JIT path remains the preferred path whenever executable code memory is available. - Fresh-launch worker preparation remains intact. - The persistent CPU worker and condition-variable wait model remain intact. - The configured iOS JIT script protocol is still applied by the existing gate. - `CS_DEBUGGED` validation remains intact. - Master's writable code-memory canary remains intact. - The 12-second idle validation interval is unchanged. - The canary is skipped while the VM or CPU initialization is active. - JIT-enabled sessions retain EE, IOP, VU0, VU1, VIF, software-GS, fastmem, and MTVU acceleration as configured. - Temporary No-JIT fallback does not overwrite the user's saved recompiler preferences. - No interpreter cache lookup is performed by `recExecute()`. ## Hybrid JIT validation synchronization `DarwinMisc` now owns a private mutex covering the validation canary and executable mapping lifetime. The synchronization sequence is: 1. Mapping address, size, and alias offset are published while holding the validation mutex. 2. `ValidateJITAlive()` first checks whether CPU work is active. 3. An idle validation takes the mutex before reading or touching the mapping. 4. The original byte and page protection are restored before releasing the mutex. 5. Mapping teardown takes the same mutex, clears the published mapping state, and only then unmaps the aliases. `WaitForJITValidation()` gives the iOS worker an explicit drain point: - Before gameplay, the worker marks itself active, stops future periodic validation, and waits for any callback which already passed the idle check. - Before backend teardown, it stops validation and waits for the same lifetime boundary before `CPUThreadShutdown()` releases executable memory. The keep-alive dispatch source has separate ownership synchronization so concurrent start/stop operations do not create multiple timers or race timer release. Interpreter-only sessions never start the keep-alive timer because they have no executable mapping and no JIT grant to preserve. ## No-JIT boot flow When JIT is unavailable, the boot-scoped runtime flow is: 1. The iOS JIT gate requests interpreter mode for the new CPU worker. 2. VM data memory is allocated normally. 3. Executable code memory is omitted. 4. Recompiler providers are not reserved or initialized. 5. Runtime configuration is clamped to the providers which actually exist. 6. EE and IOP select their interpreter implementations. 7. VU0 and VU1 select their interpreter implementations. 8. VIF uses precompiled unpack functions. 9. Software GS uses its C setup, scanline, and edge functions. 10. Fastmem and MTVU are disabled for that boot. 11. The JIT keep-alive timer is not created. If the initial JIT gate succeeds but executable allocation subsequently fails, allocation now falls back to the same interpreter path instead of aborting the boot. These are runtime capability overrides. Saved JIT, fastmem, VU, and MTVU preferences are not rewritten, so a later worker created with valid JIT access can use the configured accelerated path again. ## Safe provider and memory handling `SysMemory` exposes two explicit capabilities: - `IsAllocated()` distinguishes an initialized VM memory map from early settings loading. - `HasCodeMemory()` identifies whether native code generators can be used. This distinction prevents startup settings loading from being mistaken for a No-JIT VM while allowing every code-generation path to gate itself after allocation. Provider initialization is tracked explicitly. Shutdown and cache-reset paths therefore avoid touching recompilers which were never constructed. Releasing the memory map also clears the recorded JIT address range, preventing later diagnostics or validation from treating released memory as live code. ## VIF and MTVU fallback Generated VIF unpackers share the executable VM allocation. `CanUseVifDynarec()` now describes the actual runtime capability: generated VIF support must be compiled in and executable code memory must exist. The capability check covers: - Standard VIF unpack dispatch. - MTVU unpack dispatch. - VIF reset. - Mode-zero unpack tables. When generated mode-zero entries do not exist, VIF uses the existing precompiled C function table instead of dereferencing an uninitialized generated-function pointer. MTVU is disabled in interpreter-only mode because its VIF path depends on generated unpack execution. ## Software GS fallback The software renderer no longer resets, queries, or emits into its native scanline cache when code memory is absent. Interpreter-only execution selects: - `CSetupPrim` - `CDrawScanline` - `CDrawEdge` when antialiasing requires it The normal generated software renderer remains unchanged when JIT memory exists, and the Metal hardware renderer is not replaced by this fallback. ## Fastmem behavior No-JIT execution does not emit fastmem accesses, so interpreter-only sessions skip the 4 GB virtual-address reservation and force fastmem off for that boot. Settings reloads cannot silently re-enable fastmem against a missing reservation. The existing iOS behavior for a genuine fastmem allocation failure also remains: the VM continues without fastmem instead of terminating startup. ## Persistent-worker backend switching The CPU worker records whether it was initialized with JIT capability. When a later boot requests a different backend: 1. The current worker receives an exit request. 2. Idle validation is stopped and drained. 3. `CPUThreadShutdown()` releases the matching providers and mappings. 4. The exiting worker clears its creation/backend state and notifies waiters. 5. The caller waits for actual teardown rather than relying on a fixed sleep. 6. A new worker is created for the requested backend. This prevents overlapping workers, duplicate memory reservations, and reuse of stale JIT mappings. ## Conservative EE interpreter block cache The new `no-jit-improvements` component accelerates only the EE interpreter. ### Cache structure - 4,096 direct-mapped cache slots. - Up to 16 EE instructions per slot. - Fixed process-lifetime allocation; no heap allocation occurs in the execution loop. - Each entry stores the original instruction words and pointers to their decoded opcode descriptors. - Cache entries are aligned to reduce false sharing and keep slot access predictable. ### Execution On a cache hit, the interpreter reuses the decoded opcode descriptors and executes the short sequence through the existing interpreter functions. It stops immediately if: - The program counter no longer matches the expected instruction. - An exception or other control transfer changes the PC. - A branch boundary is reached. If the address cannot be cached safely, the original one-instruction `execI()` path is used. ### Correctness safeguards - Instruction bytes are compared with current emulated RAM before every reuse. - Blocks terminate after branches, stores, and COP0 instructions which can change memory or address-translation state. - EE cache-clear notifications eagerly invalidate overlapping entries. - A complete reset occurs at interpreter reset and shutdown. - Large or wrapping invalidation ranges trigger a complete cache reset. - Debug/development oracle configurations retain the original instruction path. - The cache is disabled when EE cache emulation requires an instruction view which differs from RAM. This is intentionally conservative. It does not add direct-threaded dispatch, superinstructions, or new MMI/VU NEON implementations. ## ThinLTO for the iOS core The iOS Xcode generation script now enables `LTO_PCSX2_CORE`. PCSX2's existing CMake support applies interprocedural optimization to the selected core source set. This can reduce native call and optimization boundaries in both JIT-enabled and interpreter builds. ThinLTO does not alter the runtime-generated EE JIT blocks and is not expected to transform JIT performance. Its largest relevance here is reducing host-side overhead around the interpreter and core helpers. ## iOS build stability The generated Xcode target uses per-file optimized Swift compilation with batch mode disabled. This limits peak compiler memory use for the large SwiftUI source set while preserving optimized Release emission. This is a build-time setting and adds no runtime work. ### Idle menu The existing 12-second validation cadence is unchanged. Each idle check validates one mapping byte, restores it, and exits. Interpreter-only workers create no validation timer. ### No-JIT resource use Interpreter fallback avoids resources which cannot improve No-JIT execution: - No EE/IOP/VU native code caches. - No generated VIF cache. - No software-GS JIT cache. - No 4 GB fastmem virtual reservation. - No MTVU worker dependent on generated VIF execution. - No JIT keep-alive source. No-JIT remains materially slower than a valid ARM64 recompiler. The purpose is safe boot plus a measurable reduction in interpreter overhead, not parity with JIT. ## Behavior matrix | Runtime state | EE/IOP | VU0/VU1 | Code cache | Fastmem | MTVU | VIF | SW GS | Keep-alive | |---|---|---|---:|---:|---:|---|---|---| | Valid JIT grant | Recompiler as configured | microVU as configured | Allocated | Configured/available | Configured | Generated | Generated | Idle only | | No `CS_DEBUGGED` grant | Interpreter | Interpreter | None | Off | Off | Precompiled | C functions | Off | | Executable allocation failure | Interpreter | Interpreter | None | Off | Off | Precompiled | C functions | Off | | Active JIT gameplay | Recompiler as configured | microVU as configured | Allocated | Configured/available | Configured | Generated | Generated | Stopped | ## Files changed ### JIT lifecycle and iOS worker - `common/Darwin/DarwinMisc.cpp` - Synchronizes validation with executable mapping publication and release. - Preserves and safely drains the writable code-memory canary. - `common/Darwin/DarwinMisc.h` - Documents the interpreter capability override and exposes the validation drain API. - `platforms/ios/app/src/main/cpp/IOS/SceneDelegate.mm` - Adds backend-aware persistent-worker recreation and keep-alive ownership synchronization. - `platforms/ios/app/src/main/cpp/ios_main.mm` - Prevents settings repair from re-enabling recompilers during an interpreter-only boot. ### Runtime capability and No-JIT fallbacks - `pcsx2/Memory.cpp` - `pcsx2/Memory.h` - `pcsx2/VMManager.cpp` - `pcsx2/Vif_Dynarec.h` - `pcsx2/Vif_Unpack.cpp` - `pcsx2/MTVU.cpp` - `pcsx2/GS/Renderers/SW/GSDrawScanline.cpp` - `pcsx2/vtlb.cpp` - `pcsx2/vtlb.h` These files make executable code memory an explicit capability and gate EE, IOP, VU, VIF, software-GS, fastmem, and MTVU behavior accordingly. ### EE interpreter performance - `pcsx2/no-jit-improvements.cpp` - `pcsx2/no-jit-improvements.h` - `pcsx2/Interpreter.cpp` - `pcsx2/CMakeLists.txt` These files implement and register the validated predecoded EE block cache. ### iOS build configuration - `platforms/ios/scripts/generate-ios-xcode.sh` - Enables the existing PCSX2 core LTO target. - `platforms/ios/app/src/main/cpp/CMakeLists.txt` - Uses per-file optimized Swift compilation to reduce build-time frontend memory pressure. ## Explicitly not included The subsequently evaluated POC's are absent from this PR: - Direct-threaded EE dispatch. - EE superinstructions. - New ARM64 NEON MMI implementations. - New ARM64 NEON VU implementations. `pcsx2/MMI.cpp` and `pcsx2/VUops.cpp` remain identical to the current master revision. ## Validation - Fetched and compared against the latest `origin/master`. - Confirmed the local branch and remote master resolve to the same base revision. - Full unsigned iOS IPA build completed with `platforms/ios/scripts/build-ios-ipa.sh` before packaging. - `git diff --check` completed without whitespace errors. |
||
|
|
5031a4d2ba |
iOS: gate the JIT keepalive canary on the VM being parked
The canary flip from the keepalive fix drops execute on the arena's first page, but the didBecomeActive prewarm re-runs it on every app switch while the CPU thread is executing the dispatcher on that exact page -> Instruction Abort. The old 'every caller runs parked' claim was only a comment; now ValidateJITAlive asks the scene layer for real VM/worker state and skips the probe (canary=skipped-vm-active) while anything JIT is running or still initializing. A live VM is its own proof the grant works. |
||
|
|
54191be600 |
iOS: fix Legacy-mode SIGBUS in the JIT keepalive canary
Main-thread boot crash on iOS 18 under LiveContainer (Legacy W^X mode): EXC_BAD_ACCESS KERN_PROTECTION_FAILURE in ValidateJITAlive, a strb of the 0x42 canary into the arena base page. Under a dual-mapping g_code_rw_base is the RW alias and the bare store is exactly the probe we want, but under an identity mapping it is the live r-x code page -- the EE dispatcher sits at arena offset 0 once the idle prewarm has run. The prewarm reordering exposed it: before it, the boot gate ran with no arena allocated and the canary was silently skipped. Scope the canary per mode: Legacy flips just the first page RW and back via mprotect, reporting a failed flip as alive=0 (grant died) instead of faulting; the MAP_JIT toggle mode uses Begin/EndCodeWrite. Every caller runs with the VM parked, so the brief execute-drop cannot race JIT execution. Also covers the 12s idle keepalive timer, which would hit the same fault after a prewarm. |
||
|
|
fd92b8eaea |
iOS: fix SIGTRAP race in JIT alloc when universal TXM times out
The detached Universal TXM worker thread can still be stuck in brk #0xf00d when the main thread falls back to legacy brk #0x69. Previously the old SIGTRAP handler was restored immediately after the legacy path, so a late trap from the worker hit the default handler and killed the process. Move the sigaction restore to AFTER vm_remap + mprotect complete, and add it to every error-return path. This keeps our handler installed during the entire allocation so late worker traps are caught safely. |
||
|
|
07d03a5eac |
Android: route native file creation through Java, and scope patch state per game
Two fixes that both live in the JNI layer. Folder memory cards on a user-chosen data folder crashed on the first new save. FUSE-backed shared storage denies libc file CREATION even though mkdir is already routed through Java, so SaveYAMLToFile opened a not-yet-existing _pcsx2_index with an unchecked OpenCFile and then dereferenced null. Existing saves reuse that file, which is exactly why only new saves crashed. Null-check the write, and add a CreateFileViaJava fallback in OpenCFile so a denied create is retried through the Java file API - the same libc/Java asymmetry that CreateDirectoryPath already relies on. Patch and cheat enable-state was written to the base settings layer, keyed only by patch name, so enabling e.g. "Widescreen 16:9" for one game switched on the identically named patch in every other game. LayeredSettingsInterface returns the first non-empty layer with the game layer ahead of the base one, so upstream keys this per serial and CRC; do the same, and strip the migrated names from the base list so an empty per-game list cannot fall back through to it. The per-game INI exporter also rebuilt the file from scratch, dropping every key it does not own - the patch lists above, and per-game MemoryCards and Gamefixes overrides. Load the existing file and clear only the sections the exporter actually writes. |
||
|
|
30b778e9ec |
Android storage: fix folder memory cards on a custom data folder
libc mkdir() is denied on the FUSE-backed emulated storage Android hands out for
a user-chosen data folder, while java.io.File.mkdirs() on the same path succeeds.
FileSystem::CreateDirectoryPath went straight to mkdir() and returned failure, so
every folder-memory-card save-data creation failed: "Format failed", and a crash
on first save in Soul Calibur 2 / Ratchet & Clank / GT4. Reproduced only with a
custom data folder, never with internal app storage.
A Java bridge for exactly this existed (NativeApp.createDirectoryPath plus the
FileSystem::CreateDirectoryViaJava JNI) but nothing called it after the monorepo
migration - the linker was dropping it as dead code. Wire it in as a fallback on
EPERM/EACCES, in both the flat and per-segment recursive paths.
Also adds folder-card import, which had no working route at all: a folder card is
a directory plus a _pcsx2_superblock marker, but the picker was OpenDocument()
(files only), so people zipped them and the importer appended ".ps2" to the
archive and copied it verbatim - producing a card the core read as unformatted.
Directories can now be imported directly, zips are unpacked, and both validate
the superblock instead of silently producing a broken card.
(cherry picked from commit
|
||
|
|
77d008af1d |
iOS W^X: route every JIT code write through the dual-map RW alias
Port the W^X protocol from the previous ARMSX2 recompilers (aR*/aVU) onto the transplanted JIT so it runs under all four DarwinMisc JIT modes: Simulator (MAP_JIT + pthread_jit_write_protect_np toggle), iOS 26 LuckTXM and LuckNoTXM (vm_remap dual-mapping, writes at rx + g_code_rw_offset), and Legacy (mprotect RW/RX toggle, iOS <= 18). - AsmHelpers: export armGetWritableCodePtr (RX -> RW alias, identity off Apple); armStartBlock/armEndBlock switch to BeginCodeWriteRange with a 1 MiB Legacy write window and construct the MacroAssembler over the RW alias while armAsmPtr stays the RX base, so armGetCurrentCodePointer() and all displacement math remain in execute space; armEmitJmpPtr and the constant-pool trampoline/literal writes go through the alias with their own write scopes. - Arm64BaseBlocks::PatchAtomic (block linking + exception-path unlink) and recPatchIslandB store via the alias; displacements/icache flushes stay RX. - RecStubs fastmem backpatch stores the redirect B via the alias. - microVU: the persistent per-VU MacroAssembler is built over the alias of prog.x86start; ProgCache hydration fixups patch through the alias while Rel26/ADRP math keeps using the RX chunk address. - recExecute re-arms Legacy-mode execute protection via DarwinMisc::LegacyEnsureExecutable (mirrors the previous recompiler). - BeginCodeWrite/EndCodeWrite skip the macOS MAP_JIT toggle when a dual-mapping is active (offset != 0), matching the iOS branches. - CI validation without an iOS device: ARMSX2_FORCE_DUAL_MAP=1 now also works on macOS (Memory.cpp routes the code arena through DarwinMisc::MmapCodeDualMap, which builds the vm_remap RW alias there), and the macOS workflow reruns recompiler_tests under it, forcing every emission/patch path through the alias. Production macOS keeps MAP_JIT with offset 0, unchanged. Linux/Android paths compile to identity no-ops. Gates: recompiler_tests 1359/1359, gs_vertex_tests 21/21, mvu_progcache_versioning_tests 13/13. |
||
|
|
e6fdc666f2 |
common: drop __vectorcall from the arm64 r128 calling-convention macros
__vectorcall is an x86-ism; AAPCS64 already passes/returns 128-bit
vectors in SIMD registers under the default calling convention, and
the macro expands to nothing on non-Windows anyway. On aarch64-windows
clang-cl folds it to an explicit default-CC (cdecl) attribute, which
conflicts with the preserve_most annotation on the vtlb r128
dispatchers ('preserve_most and cdecl attributes are not compatible',
8 errors across every TU including vtlb.h) while changing nothing
about how r128 is actually passed. The x86 branch keeps __vectorcall
untouched.
recompiler_tests 1359/1359 on linux-arm64.
|
||
|
|
3e077eff9b |
Merge yaps2: arm64 JIT transplant + test/perf/libretro infrastructure
Merges yaps2/main (github.com/yaps2/yaps2, |
||
|
|
ef70ec633e | Merge branch 'pcsx2master' | ||
|
|
8aba55e4e9 |
emitter/arm64: fix Windows-arm64 link error on x86Emitter::rbx
VMManager.cpp (compiled on every target) includes x86emitter.h, which
pulls in x86types.h. That header binds `RTEXTPTR` as a reference to the
x86 register `rbx`:
static constexpr const xAddressReg& RTEXTPTR = rbx;
`rbx` is defined only in x86emitter.cpp, which CMake compiles solely
under ARCH_X86. Binding the reference ODR-uses `rbx`, so on ARM64 it
needs a definition that does not exist. clang (macOS/Linux arm64) dead-
code-eliminates the unused reference and links fine, but MSVC keeps it,
so the Windows-arm64 link failed:
VMManager.cpp.obj : error LNK2001: unresolved external symbol
"class x86Emitter::xAddressReg const x86Emitter::rbx"
pcsx2-qt.exe : fatal error LNK1120: 1 unresolved externals
RTEXTPTR is an x86 concept (the program-text pointer register) and every
real user lives in pcsx2/x86/** or common/emitter/*.cpp, all ARCH_X86-
only and never built on arm64. Gate the alias to _M_X86 so it simply
doesn't exist on arm64 -- no behavior change on x86, and the spurious
rbx reference disappears on Windows arm64.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
04ea993e99 | Merge remote-tracking branch 'armsx2/master' into ios/pr-ready | ||
|
|
ac552ea3e0 |
common/FPControl: MSVC arm64 path for FPCR read/write
MSVC's arm64 cl.exe rejects GCC inline asm (asm volatile mrs/msr FPCR), which broke the Windows arm64 build (C2059 syntax error: 'volatile', cascading to 100+ errors per TU). Read/write FPCR via the system-register intrinsics _ReadStatusReg/_WriteStatusReg(ARM64_FPCR) under (_MSC_VER && !__clang__); clang/clang-cl keep the inline asm. <intrin.h> (which declares these) is already included by VectorIntrin.h under _MSC_VER. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
d57633224d |
iOS: merge upstream/master into ios/pr-ready
Resolve two conflicts: Threading.h: keep upstream's doc comment for SetNicePriority VMManager.cpp: keep our iOS-aware guard that suppresses the controller warning on both Android and iOS, replacing upstream's Android-only comment-out hack |
||
|
|
fb2c07eb6e |
iOS: add JIT resilience layer with keepalive, interpreter fallback, and boot watchdog
Build a comprehensive JIT resilience layer that prevents silent black screens when iOS revokes the CS_DEBUGGED grant after approximately 30 to 60 seconds of app inactivity. Add a ValidateJITAlive helper to DarwinMisc that re-probes CS_DEBUGGED via csops and writes a canary byte to the JIT RW alias to detect whether the mapping is still writable, covering the case where the flag lingers but the underlying grant is already dead. Add a 12-second dispatch timer in SceneDelegate that calls ValidateJITAlive while the VM is idle, skipping during active gameplay since the recompiler keeps JIT in constant use, and posts a JITExpired notification on detection. Add interpreter fallback to the boot gate so that when JIT is dead the app falls back to the pure EE, IOP, VU0, and VU1 interpreter instead of blocking boot, wiring up the previously dormant iPSX2_FORCE_EE_INTERP flag and fixing applyFullInterpreterPreset to actually write EnableEE equals false since CoreType was an iOS-UI-only concept the C++ core ignored. Skip executable code-memory allocation in Memory.cpp when in interpreter mode since the interpreter does not generate native code, and null-guard SetJitRange to prevent recording bogus JIT ranges. Add a 15-second VM init watchdog that catches TXM prepare hangs and shows an error dialog instead of leaving a permanent black screen. Add an 8-second timeout to the Universal TXM prepare path by running the brk number 0xf00d cycle on a detached worker thread with thread_local sigjmp_buf, falling back to the Legacy brk number 0x69 protocol on timeout. Add re-boot JIT revalidation so the persistent VM thread validates JIT before signaling, resetting to interpreter mode with s_vmThreadShouldExit to cleanly tear down and recreate the thread with paired CPUThreadShutdown. Restore recompiler settings and fastmem when JIT returns on next app launch. Add the design spec and a user-facing JIT troubleshooting guide documenting black screen causes, interpreter fallback expectations, diagnostic log markers, and workarounds. |
||
|
|
431ca0c063 |
iOS: port JIT and W^X foundation, refresh SwiftUI frontend, fix critical boot and display bugs
Port the complete JIT and write-xor-execute infrastructure to DarwinMisc with four JitModes (Simulator, Legacy, LuckTXM, LuckNoTXM), dual-mapping via vm_remap for writable code aliases, the csops CS_DEBUGGED probe for JIT availability detection, brk assembly helpers for the TXM protocol, and the W^X toggle functions. Connect the JIT foundation to the code emitters through AsmHelpers dual-map bridge, Memory.cpp MmapCodeDualMap allocation, and the aR5900 LegacyEnsureExecutable path. Refresh the iOS SwiftUI frontend from the iOS-refresh branch, bringing in 11 missing and 20 drifted Swift files plus ios_main.mm integration. Switch the CI to a real device build using the iphoneos SDK. Fix the Achievements crash by gracefully degrading when no HTTPDownloader is available (no CURL on iOS). Fix the Metal surface to reuse the UIView's existing CAMetalLayer instead of an orphaned allocation that caused half-screen crops. Fix GS memory allocation by using mmap and vm_remap instead of shm_open which is blocked by the iOS sandbox. Suppress the false positive Graphics not Automatic OSD warning. Merge upstream master and resolve all resulting compile errors. |
||
|
|
14fc29c0cd |
iOS: gate macOS-only APIs behind TARGET_OS_IPHONE and add frontend link stubs
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. |
||
|
|
b5e581b1f3 |
iOS: remove Android and React Native source, wire CMake build system, and add self-contained build workflow
Strip the legacy Android, React Native, Java, Gradle, and res/ directories from platforms/ios that were inherited from the original port. Configure the CMake build for the iOS target with local module discovery, PCAP and CURL guards, rapidyaml source path fixes, Vulkan disabled, lz4 build flags scoped, libjpeg-turbo skipped on iOS, and the Qt UI and test runners turned off. Set CMAKE_SYSTEM_PROCESSOR to arm64 for cross-compilation. Add a self-contained GitHub Actions workflow that builds an unsigned IPA for real devices using the iphoneos SDK, named with the commit SHA. Merge upstream master to stay current. |
||
|
|
5e3ad282a8 | common: Fix build on ryml < 0.11 | ||
|
|
98c90a2124 |
Android 2.5.8: OSD off-by-default + rumble + MP4 wallpaper + controller keyboard/nav
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. |