Commit Graph
360 Commits
Author SHA1 Message Date
J1coding 06bb419db9 iOS: shorten the longest comment blocks in the hack code
Tightens the new comments this branch added and the longest blocks it
sits next to, so every file it touches lands at or under the comment
density it started with.

Two of the trimmed blocks described what the code no longer does, which
is the kind of comment that goes stale without anyone noticing.
2026-08-06 17:10:11 +02:00
J1coding 79a12a4194 GS: fold base hack claims back in under a game file
LoadCoreSettings ORs the base layer's UserHackOverrides into the mask it
just loaded, before the masks run.

The game settings layer replaces that key rather than merging into it,
so a game with its own file silently dropped every claim the player had
made globally, and the database took those hacks straight back. The
frontend used to compensate by freezing the global mask into each game
file at save time, which is how stale claims ended up pinned there
forever.
2026-08-06 17:10:11 +02:00
J1coding 77c91fb8c5 iOS: save the per game renderer through the shared write path
The renderer write goes through the same useCurrent helpers as every
other per game key, and CheckForConfigChanges keeps a running game on
the renderer it booted with, iOS only.

Mid game the old forISO write resolved identity through a cache only
lookup that can silently miss, and even a hit can land the key in a
different file than the panel reads back and the boot path loads, so
the selection quietly vanished. The file only bypass never dodged the
live apply either: sibling writes in the same save trigger the same
debounced reload, and a renderer change in that reload would reopen GS
and tear the Metal device down under the running game.
2026-08-06 11:52:40 +02:00
Brandon 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.
2026-07-31 15:56:20 +02:00
J1coding b55607c4bf VMManager: keep fastmem off once its reservation has failed
Fastmem wants a 4 GB virtual reservation and does not always get one on a
small device under LiveContainer. That case is handled: the area is marked
permanently unavailable and EnableFastmem is forced off. The INI still says
fastmem is on though, so every settings reload turns it back on, and the
disable was being re-applied by hand afterwards at each call site. Two of the
three had it. ApplyCoreSettings, which runs on every ELF change, did not.

You can see it happen in a DOA2 log from an iPhone SE 2. The EE dispatcher is
956 bytes when the game boots and 968 after the ELF lands, and the twelve
bytes between are the fastmem base load in _DynGen_EnterRecompiledCode, which
is the only runtime config dependent branch in that whole region. On a device
where the reservation succeeds it is 968 both times.

So the build ends up with CHECK_FASTMEM true and not one fastmem mapping:
codegen emits the fastmem paths, the backpatch handler has nothing to resolve
against, and the base register holds null. Whether that is what killed the
run in that log I cannot show, and the immediate consequence of the flip is
harmless because vtlb_ResetFastmem checks the sticky flag and returns. It is
still a state the emulator should never be in.

Moved the disable into LoadCoreSettings, which both reload paths go through,
and dropped the two hand-written copies. One place to get it right, and a
reload path added later cannot quietly miss it. The warning stays but fires
once now, since an ELF change would otherwise repeat it.
2026-07-30 21:31:17 +02:00
jpolo1224 3cb1e88029 Merge remote-tracking branch 'origin/master' into jit-android-catchup-gv7
# Conflicts:
#	tests/ctest/core/gs/CMakeLists.txt
2026-07-30 01:10:19 -04:00
jpolo1224 de7ec8509c GS: 20:9/19.5:9/custom aspect, interlace+presentation policies, VK feedback flags
Aspect ratios: added 20:9, 19.5:9 and a user-entered Custom ratio
(GSOptions::CustomAspectRatio, clamped 0.5..5.0). All APPENDED, never inserted —
these values are persisted as raw ints in the ini and in the Android prefs, so
slotting one in mid-enum would silently repoint every saved config at a different
ratio. Also filled in the two ultrawide cases RequestDisplaySize was missing.

Interlace/presentation: ported sashkinbro's EmuCoreX 30799e4. SelectGSInterlaceMode
centralises the mode choice and keeps shader_mode -1 for automatic full-frame output
(a deinterlace pass must not run over progressive output during a video-mode
transition); our formula already agreed, so this is centralisation plus
static_asserts rather than a behaviour change. ShouldSkipAndroidBlankFrame is new
behaviour: Vulkan now suppresses only the startup blank, so a mid-game fade reaches
the normal present path and its recorded command buffer is submitted.

Vulkan: declare the attachment feedback loops on the PIPELINE, not just on the image
layout and render pass. We put attachments into FEEDBACK_LOOP_OPTIMAL without ever
setting VK_PIPELINE_CREATE_{COLOR,DEPTH_STENCIL}_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT,
which the spec requires — undefined behaviour rather than a missed optimisation, and
strict mobile drivers are where undefined shows up as stale attachment reads.
2026-07-30 01:09:12 -04:00
Brian Degenhardt 365c0e2eaf Merge pull request #402 from ARMSX2/help-menu-and-branding-fixes
Fix Help menu and rebrand user-facing PCSX2 references to ARMSX2
2026-07-29 20:47:08 -07:00
J1coding 0d5c6674ab VMManager: actually strip manual hacks before the ELF boots
ApplyGameFixes clears ManualUserHacks on the pre-ELF path and returns, with a
comment saying it is disabling the player's manual hardware fixes because they
might be problematic on the BIOS.

It is not disabling them. MaskUserHacks already ran back in LoadCoreSettings,
while the flag was still set, so it took its early return and left every hack
in place. Clearing the flag afterwards changes nothing that has already been
loaded, and the return skips the MaskUpscalingHacks call at the bottom too. The
hacks stay live on the BIOS screen and through the boot logo.

Mask both after clearing the flag, so the code does what it says.

Worth knowing this shifts behaviour for anyone who had manual hacks on and was
seeing them apply before the game started. That was the bug, not a feature, but
it will look like a change.
2026-07-29 20:18:58 +02:00
Brandon 37ce96996c iOS: Optimize the Menu Runtime and Add Fluid Liquid Glass Game-Card Transitions
# iOS: Optimize the Menu Runtime and Add Fluid Liquid Glass Game-Card Transitions

## Summary

This pull request improves the iOS menu and gameplay handoff while preserving the existing emulator behavior.

The main changes are:

- Keep one shared menu background alive across Games, BIOS, and Settings instead of recreating it during normal tab changes.
- Preserve video-background playback position and audio continuity.
- Hold a temporary background-only frame while iOS suspends the live renderer, then release that frame after the renderer resumes.
- Reduce Game Library work during scrolling, refreshes, cover lookup, and thumbnail decoding.
- Add live SwiftUI Fluid Zoom transitions for game launches and game-card context menus.
- Make the enlarged context-menu card use interactive Clear Liquid Glass instead of an opaque preview.
- Improve the Now Running card, running-cover glow, large-title behavior, BIOS presentation, and retained native tab interface.
- Gate game boot when JIT access is unavailable and present a useful warning instead of entering an unusable boot.
- Finish Emulation-Only Mode only after its native resource teardown completes, including BIOS-only boots.

The changes are limited to the files included in this archive.

## Comparison Against Master

This report and archive were regenerated after fetching the latest remote master branch.

- Base: `origin/master`
- Base commit: `7b89374919d0`
- Local `HEAD`: `7b89374919d0`
- Working-tree difference: 19 modified files
- Diff size: 3,218 insertions and 605 deletions
- Added or deleted tracked files: none

Because local `HEAD` and the fetched remote master are the same commit, every file in the ZIP represents an uncommitted modification directly against the current master base. Older ZIP files, IPA products, generated Xcode files, and unrelated untracked documents are not included.

## Complete User-Facing Changelog

### Quality-of-Life Guidance

The app now gives users a clear result at the points where setup or lifecycle state previously appeared to do nothing:

- Starting a game or using **Boot BIOS** without a bootable BIOS presents **“BIOS not yet imported.”**
- Starting or restarting a game without JIT presents **“JIT Access Not Detected”** and explains how to match the StikDebug script to the JIT Script setting.
- A normal tap on a game card remains the direct Play action; it is separated from the favorite control and long-press context menu.
- Returning to the menu while a VM is active presents a stable **Now Running** card with Resume and Stop actions.
- Confirming Stop immediately changes the running presentation into an animated **Stopping…** state so shutdown no longer looks like an ignored or abrupt action.

### Fixed

- Fixed the black background shown after putting the app in the app switcher and returning.
- Fixed custom video backgrounds restarting from zero during normal menu/background lifecycle changes.
- Fixed the Game Library's empty, portrait, grid, list, and landscape cover-flow alignment.
- Fixed stale scroll position and layout reuse after rotating between portrait and landscape.
- Restored the intended iPad navigation-tab placement rather than applying compact iPhone placement.
- Fixed the enlarged selected-game preview using an opaque background; it now uses interactive Clear Liquid Glass with transparent hosting.
- Fixed Game-Card Zoom failing on first launch, before a thumbnail finishes, after confirming **Restart VM**, in list mode, in portrait grid, or in landscape cover flow.
- Fixed the selected cover image missing during Game-Card Zoom by performing a bounded selected-card downsample when necessary.
- Fixed the library disappearing abruptly beneath the zoom; it now fades while emulation starts immediately.
- Fixed long-press context menus so the complete card, cover, text, favorite state, tint, transparency, and Liquid Glass surface enlarge together.
- Fixed the favorite star being placed behind the card or replacing the main card interaction.
- Fixed **Now Running** appearing during the initial transition into gameplay; it is retained for the menu return state.
- Fixed **Now Running** disappearing between a running VM and a confirmed replacement VM.
- Fixed the **Now Running** card snapping away or causing the remaining Game Library glass to rematerialize.
- Fixed the running-cover highlight by scoping a fading neon-green glow to only the active game's decoded cover.
- Fixed Games, BIOS, and Settings large-title positions being inconsistent between empty and populated states.
- Fixed retained Games/BIOS titles disappearing after pull-to-scroll and tab changes.
- Fixed the compact toolbar title colliding with **Boot BIOS**.
- Fixed toolbar/title changes briefly showing the wrong tab name.
- Fixed the Games/BIOS/Settings page transition so large titles and shared toolbar controls morph or fade instead of abruptly replacing one another.
- Fixed the iOS 17/18 navigation bar appearing as an opaque rectangular strip instead of a compact floating pill.
- Fixed the selected iOS 17/18 tab indicator being too dark, too narrow, or unanimated.
- Fixed tab content drawing under the foreground native tab bar.
- Fixed tab navigation being limited to taps by adding guarded left/right swipe navigation.
- Fixed hidden retained BIOS and Settings pages performing unnecessary work before their first activation.
- Fixed BIOS-only Emulation-Only startup waiting indefinitely for game-specific patch/texture barriers.
- Fixed Emulation-Only Mode removing its SwiftUI presentation before native optional-resource teardown finishes.

### Added

- Added instant VM startup while the Fluid Game-Card Zoom animation runs independently above the menu-to-game transition.
- Added a live SwiftUI Fluid Zoom card for normal game launches.
- Added a live SwiftUI Liquid Glass context-menu preview for long-pressed cards.
- Added a new compact, translucent, pill-shaped navigation tab bar for iOS 17/18.
- Added a spring-animated, monochrome-blue selected-tab pill for iOS 17/18.
- Added native tab-bar handling for iOS 26 while retaining the platform Liquid Glass selection behavior.
- Added swipe-left and swipe-right navigation between Games, BIOS, and Settings, including right-to-left layout support.
- Added gesture arbitration so tab swipes do not steal sliders, controls, navigation-edge gestures, or horizontal Game Library scrolling.
- Added page-owned Games, BIOS, and Settings titles with matched-geometry morphing during tab changes.
- Added persistent Games/BIOS toolbar ownership so **Boot BIOS** and toolbar symbols morph through the shared navigation hierarchy.
- Added a single persistent background renderer shared by the retained menu tabs.
- Added a background-only suspension snapshot system to avoid a black frame in the app switcher.
- Added live-renderer warm-up followed by snapshot fade and pixel-memory release after returning to the app.
- Added current-frame capture support for local video backgrounds.
- Added video playhead preservation across pause, backgrounding, and renderer recreation.
- Added downsampled static wallpaper loading and bounded animated-wallpaper decoding.
- Added a multi-stage **Now Running → Stopping…** transition with symbol replacement, action fade, text morph, glass shrink, and final removal.
- Added an isolated transient glass container so removing **Now Running** does not change the remaining card material.
- Added per-running-cover randomized neon glow animation with teardown fade.
- Added a **JIT Access Not Detected** boot gate that retains the requested game until the user retries or cancels.
- Added indexed cover lookup, coordinated thumbnail decoding, refresh coalescing, and metadata caching for the Game Library.
- Added native completion notification handling for Emulation-Only optional-resource teardown.

## User-Visible Changes

### Fluid Game-Card Zoom

Selecting a game can now transition from the actual library card into gameplay using a live SwiftUI card rather than an enlarged screenshot.

The transition carries:

- The decoded cover image.
- Game title and file information.
- List, grid, or landscape cover-flow geometry.
- The card's corner radius.
- Favorite state.
- Clear Liquid Glass styling.

The VM boot starts immediately; the menu fade and zoom run as presentation work above it. The live card remains visible long enough for the zoom to complete and then fades into the active emulation surface. The transition does not retain the entire Games screen.

The existing **Game-Card Zoom Animation** setting continues to control the game-launch transition.

The transition builder also handles the cases that previously skipped or lost the animation:

- The first game tapped after launch.
- A cover whose asynchronous thumbnail has not completed.
- A game started from list mode.
- A game started from portrait grid mode.
- A game started from landscape cover flow.
- A replacement game started after confirming **Restart VM**.

### Context-Menu Card Preview

Long-pressing a game card uses SwiftUI's custom context-menu preview path:

- The cover, text, favorite indicator, padding, and glass surface scale together.
- The system context menu performs the lift and return transition.
- The enlarged card is rebuilt as live SwiftUI content rather than scaling a stale rasterized snapshot.
- The preview explicitly receives the Clear Liquid Glass preference because the system renders it in a separate context-menu host.
- The preview uses interactive glass behavior, transparent hosting, the existing app tint environment, and the same continuous corner geometry.
- The previous custom dark outer shadow was removed so the preview does not appear to have an opaque background.

This work applies to list cards, portrait grid cards, and landscape cover-flow cards.

### Favorite Controls

The favorite button remains part of the complete card hierarchy and stays above the cover and Liquid Glass surface.

Favorite changes use symbol animation without replacing the card's main tap target or context-menu interaction.

### Now Running

The retained Now Running card has a dedicated stopping presentation:

- The running controls transition into a stopping state.
- Status content fades before removal.
- The Liquid Glass card scales and fades to zero.
- The remaining library is isolated from the transient card's glass container so its glass properties do not snap when removal completes.
- Restarting into a different game preserves the running-card continuity instead of briefly removing it between VMs.

The active game's cover receives a randomized neon-green glow. Only the running cover owns this animation, avoiding a library-wide animation timeline. The glow fades when the game stops.

### JIT Boot Warning

Game launch now checks JIT availability before starting or restarting a VM.

When JIT access is missing, the app presents:

> JIT Access Not Detected

with the guidance:

> JIT access is not available. Match the StikDebug script to the JIT Script setting in Emulator settings.

The pending request retains the selected game and its launch transition so the boot can continue after JIT access becomes available. Cancelling clears that request.

### BIOS Setup Warning

Game and BIOS-only boot paths share one bootable-BIOS check. If no valid BIOS has been imported, the request does not enter a black or incomplete gameplay screen; the app presents:

> BIOS not yet imported.

This applies whether the user starts from a game card or the always-available **Boot BIOS** control.

### Direct Game-Card Interaction

The complete card is the primary Play button:

- Tap starts or resumes the selected game.
- Tap on the star changes favorite state.
- Long press presents Game Info, Per-Game Settings, Cheats & Patches, Covers, Disc Path where applicable, cache clearing, and deletion actions.

The nested controls retain separate hit targets without turning a normal Play tap into a brief zoom-only action.

## Game Library Performance

### Indexed Cover Lookup

A library refresh now builds one immutable filename index for the relevant cover directories.

Previously, cover resolution could enumerate the same directories for each game. The new lookup:

1. Enumerates each unique managed, game-local, and fallback directory once.
2. Normalizes filenames into an in-memory dictionary.
3. Resolves every game against that snapshot.

This reduces filesystem enumeration as the library grows.

### Bounded and Shared Thumbnail Decoding

Cover thumbnail decoding now uses a shared coordinator:

- Identical in-flight requests share one decode task.
- Unique ImageIO decodes are bounded to six concurrent operations.
- Decoding runs away from the main actor.
- Completed images still enter the existing thumbnail cache.
- A generation guard prevents late decoding work from repopulating a cache released for gameplay.

When a selected cover has not finished its asynchronous thumbnail task, the Fluid Zoom transition performs one bounded downsample for that selected card. This avoids a missing cover without forcing every card to decode synchronously.

### Cached Display Metadata

Frequently rendered game-card strings and identifiers are computed when `ISOEntry` is created:

- Display title.
- Formatted size.
- Region flag.
- Normalized running-game identifiers.

This avoids repeating path, formatting, and normalization work during SwiftUI body evaluation.

### Refresh and Persistence Work

The library runtime now:

- Defers or coalesces reload work while the user is actively scrolling.
- Avoids assigning an identical game list.
- Builds dictionaries with reserved capacity.
- Purges removed metadata without recreating the complete dictionary.
- Serializes the persistent metadata snapshot on a utility queue.
- Keeps transient loading, scrolling, and running-identifier bookkeeping outside SwiftUI observation.

These changes reduce full-library invalidations and main-thread file work.

### Rotation and Layout State

Portrait grid/list and landscape cover-flow presentations use separate stable identities. Rotation therefore does not reuse an incompatible scroll view's content offset or alignment geometry.

The library remains scrollable, respects the native tab bar, and uses page-owned large titles where the retained shared navigation hierarchy cannot reliably manage independent large-title state.

Landscape cover flow computes an orientation-specific available height and visual offset rather than inheriting portrait padding. Empty Games and BIOS presentations keep their content centered while still allowing intentional pull/bounce behavior.

## Background Runtime and Continuity

### One Persistent Renderer

The menu root owns one `PersistentMenuBackgroundHost`. Games, BIOS, and Settings reveal or hide that renderer; normal tab selection does not create a renderer per tab.

This retains:

- Dynamic Background time and renderer state.
- Video player position and audio.
- Animated background state.
- XMB palette and shader continuity.

Tabs where **Show Background In** is disabled hide the presentation without resetting a configured video.

### Backgrounding Snapshot

Before iOS suspends Metal, video, and display-link rendering, a dedicated UIKit subtree captures only the background.

The captured frame:

- Does not include menu cards, navigation titles, toolbars, or the native tab bar.
- Is shown immediately while the scene is inactive.
- Remains visible while the resumed live renderer warms up.
- Fades away after activation.
- Is removed from memory after the fade.
- Is also discarded when the background is removed or gameplay starts.

Video backgrounds first provide a rasterizable current frame because `AVPlayerLayer` content is not guaranteed to appear in a normal UIKit hierarchy snapshot.

### Video Playback Position

Local background videos save their current playhead when paused or suspended and restore it when recreated. The position is cleared only when the background session is explicitly released, preventing normal app backgrounding from restarting the video at zero.

### Static and Animated Image Memory

Static wallpapers are downsampled with ImageIO to approximately the active display size on a utility task instead of retaining the full source image.

Animated backgrounds:

- Load a static first frame independently.
- Avoid animated decode when Reduce Motion is enabled.
- Bound total decoded frame memory.
- Use a capped display-link range.
- Cancel decoding and release frames when the menu background is released.

### Dynamic Background Drawing

Eligible SwiftUI `Canvas` effects render asynchronously, reducing main-thread drawing pressure while preserving each effect's existing update rate and visual configuration.

The PlayStation 3 XMB shader library remains cached during short menu/Appearance renderer handoffs, but the cache is explicitly eligible for release at the end of the menu session or when gameplay replaces the menu.

## Navigation, Titles, and Tabs

### Retained Menu Pages

Games and BIOS share one persistent `NavigationStack`; Settings remains a retained sibling. Switching tabs changes visibility, hit testing, accessibility, and z-order without destroying and rebuilding every page.

This allows:

- Stable Liquid Glass identity.
- Persistent Games/BIOS toolbar ownership.
- No opaque rematerialization of retained page content.
- Fewer tab-change reloads.
- Correct return-to-root behavior when the selected Settings tab is tapped again.

### Consistent Page Titles

Games, BIOS, and Settings use page-owned large titles on supported phone layouts. Their top origin, horizontal inset, font, and empty/populated behavior are shared.

During a tab change:

- The title participates in one matched-geometry namespace.
- Games and BIOS toolbar items retain stable identifiers.
- The library toolbar fades when entering Settings.
- Compact-height layouts use a principal title without squeezing it beside **Boot BIOS**.

### iOS 26 Navigation Tab Bar

iOS 26 continues using the native `UITabBar` presentation so its Liquid Glass selection, tint, press feedback, and system behavior remain available. The bar is installed as a foreground safe-area sibling instead of inside the scrolling page glass hierarchy.

### iOS 17/18 Navigation Tab Bar

Earlier systems receive a dedicated compatible presentation:

- One compact ultra-thin-material outer capsule.
- A wider translucent selected-tab capsule.
- Monochrome blue selected icon and label.
- Spring movement between selections.
- Press scaling and opacity feedback.
- Centered portrait/landscape geometry.
- Home-indicator clearance in compact landscape.
- Transparent system bar background rather than the previous rectangle.

The iPad path retains its intended platform placement and does not reuse the phone's compact geometry.

### Swipe Navigation

A UIKit pan recognizer enables horizontal swipes between Games, BIOS, and Settings.

The recognizer:

- Requires a predominantly horizontal gesture.
- Uses distance plus projected velocity.
- Respects left-to-right and right-to-left tab order.
- Does not cancel the touched view.
- Avoids controls and the native tab bar.
- Protects system navigation edges.
- Yields to horizontally scrollable content such as landscape cover flow.
- Recognizes simultaneously where safe so normal vertical library scrolling remains available.

## BIOS and Settings Presentation

### BIOS

The BIOS page:

- Uses the same page-owned large-title origin as the other retained menu pages.
- Keeps empty and populated states scrollable.
- Aligns its compact-height empty state with Games.
- Avoids rescanning BIOS files while its retained tab is hidden.
- Coalesces bootstrap/import refresh notifications.
- Avoids replacing the BIOS array when its contents are unchanged.
- Keeps the Import BIOS plus symbol white inside its pill.

### Settings

The Settings root:

- Uses a page-owned large title in the retained phone menu.
- Avoids querying JIT status while the hidden tab has never been activated.
- Caches the build-version string.
- Caches DEV9 network adapters for the lifetime of the screen.
- Coalesces host-file writes while the user types and flushes them when leaving or backgrounding.

### iPad

The menu avoids applying the phone-specific page-owned large-title and compact tab-bar assumptions to iPad. This restores the intended iPad navigation-tab placement and lets the platform use the appropriate larger-screen navigation presentation.

## Emulation-Only Mode

Emulation-Only Mode still waits for the emulator's normal startup readiness barriers, including patch and replacement-texture initialization.

The teardown handoff is now two-phase:

1. Swift records the presentation that must remain.
2. Native code releases the selected optional resources.
3. Native code posts a completion notification on the main queue.
4. Swift removes the corresponding overlay/UI only after native teardown has completed.

This avoids showing a stripped UI before the native release has actually finished.

Returning temporarily to the menu and resuming the same stripped VM no longer recreates services already released by Emulation-Only Mode.

BIOS-only boot has no game ELF or replacement-texture map, so native initialization now explicitly satisfies those two readiness barriers after the VM subsystems finish initializing. This prevents automatic Emulation-Only Mode from waiting indefinitely after **Boot BIOS**.

## Gameplay Resource Impact

When gameplay replaces the menu, the existing release path now works with the optimized owners above:

- The Game Library list and metadata entries are released from the active SwiftUI hierarchy.
- Pending cover tasks are cancelled.
- The thumbnail cache stops accepting late results and releases decoded thumbnails.
- The shared menu background host releases its live renderer and inactive snapshot.
- Video player state, display links, animated-image frames, Dynamic Background renderers, and the XMB session shader cache become eligible for teardown.
- The gameplay transition retains only one selected, display-sized cover and lightweight strings until its animation completes.

Emulation-Only Mode can then release its configured optional gameplay services after patches and texture startup are ready. Core VM execution, rendering, audio, disc access, memory cards, and the preserved external-controller input path are not intentionally removed by these menu changes.

## Expected Impact

Expected improvements include:

- Less Game Library main-thread work.
- Fewer duplicate cover-directory scans.
- Fewer simultaneous and duplicate image decodes.
- Faster visible-cover reuse and reliable cover presentation in transitions.
- Lower transient memory for oversized static and animated backgrounds.
- No normal tab-change video restart.
- Less Dynamic Background recreation across retained menu tabs.
- No black background during normal app suspension/resume when a frame can be captured.
- More deterministic cleanup before gameplay and Emulation-Only Mode.
- Smoother game-card context-menu and launch animations.

No numerical CPU, GPU, memory, battery, or thermal claims are included because this archive was not accompanied by an Instruments capture.

## Validation

The following validation completed successfully:

- `git diff --check` for the final Liquid Glass context-preview changes.
- Fetched and compared against `origin/master` at `7b89374919d0`.
- Confirmed 19 modified tracked files, with no tracked additions or deletions.
- Full unsigned iOS device build using `platforms/ios/scripts/build-ios-ipa.sh`.
- Xcode 26.6 / iPhoneOS 26.5 SDK.
- Deployment target: iOS 17.0.
- Architecture: arm64.
- Result: `** BUILD SUCCEEDED **`.
- Unsigned IPA generated at `platforms/ios/build-ios-xcode/ARMSX2-iOS-unsigned.ipa`.

The build reports existing deprecation/unused-value warnings unrelated to this change set. Physical-device interaction and Instruments profiling remain recommended before merge.

## File-by-File Master Comparison

| File | Changes relative to master |
|---|---|
| `pcsx2/VMManager.cpp` | Completes patch and replacement-texture readiness barriers for BIOS-only boots so automatic Emulation-Only teardown can proceed. |
| `platforms/ios/app/src/main/cpp/ARMSX2Bridge.h` | Exposes the native Emulation-Only active-state query to Swift. |
| `platforms/ios/app/src/main/cpp/ARMSX2Bridge.mm` | Posts native optional-resource release completion and reports whether the VM remains in Emulation-Only Mode. |
| `platforms/ios/app/src/main/swift/Models/AppState.swift` | Adds live launch-card metadata, BIOS/JIT boot gates, pending JIT requests, restart continuity, menu/game handoff state, and persistent Emulation-Only presentation behavior. |
| `platforms/ios/app/src/main/swift/Models/CoverStore.swift` | Adds one-pass cover-directory indexing and indexed resolution for complete library refreshes. |
| `platforms/ios/app/src/main/swift/Views/AnimatedLibraryBackgroundView.swift` | Adds asynchronous first-frame loading, Reduce Motion behavior, decoded-memory bounds, and capped display-link scheduling. |
| `platforms/ios/app/src/main/swift/Views/BIOSListView.swift` | Unifies title/layout behavior, retains scrolling, defers hidden-tab scans, coalesces refreshes, preserves toolbar ownership, and updates Import BIOS presentation. |
| `platforms/ios/app/src/main/swift/Views/Background/BackgroundContainerView.swift` | Adds off-main static wallpaper downsampling and coordinates inactive renderer release with snapshot capture. |
| `platforms/ios/app/src/main/swift/Views/Background/Dynamic/DynamicBackgrounds.swift` | Enables asynchronous Canvas rendering for eligible Dynamic Background styles. |
| `platforms/ios/app/src/main/swift/Views/Background/Dynamic/DynamicEffects.swift` | Moves the reusable particle-overlay Canvas to asynchronous rendering. |
| `platforms/ios/app/src/main/swift/Views/Background/Dynamic/PlayStation3XMBByMartShaderLibrary.swift` | Retains the XMB shader library across short renderer handoffs and releases it at a real menu-session boundary. |
| `platforms/ios/app/src/main/swift/Views/Background/MenuBackgroundSupport.swift` | Adds persistent renderer ownership, app-switcher snapshots, warm-up fade/release, page-owned title morphing, stable/isolated glass containers, and shared background-aware menu helpers. |
| `platforms/ios/app/src/main/swift/Views/Background/VideoBackgroundView.swift` | Preserves local-video playhead state and generates a capturable current frame for inactive background snapshots. |
| `platforms/ios/app/src/main/swift/Views/CoverThumbnailView.swift` | Adds coordinated bounded decoding, duplicate-request sharing, selected-card fallback decoding, cache lifecycle guards, and gameplay release behavior. |
| `platforms/ios/app/src/main/swift/Views/GameListView.swift` | Implements the optimized library model, centered layouts, stable rotation identities, direct card/context interactions, Fluid Zoom metadata, clear preview, Now Running transitions, neon running glow, and deferred refresh behavior. |
| `platforms/ios/app/src/main/swift/Views/GameScreenView.swift` | Waits for native Emulation-Only release completion and restores an already-stripped VM without recreating released optional services. |
| `platforms/ios/app/src/main/swift/Views/RootView.swift` | Adds boot warnings, live launch overlay, retained tabs, shared toolbar/title transitions, iOS 26/native and iOS 17/18 tab-bar paths, swipe navigation, foreground z-order, safe-area handling, and root menu resource release. |
| `platforms/ios/app/src/main/swift/Views/Settings/AppearanceSettingsView.swift` | Uses the final **Game-Card Zoom Animation** label. |
| `platforms/ios/app/src/main/swift/Views/Settings/SettingsRootView.swift` | Adds consistent Settings title behavior, lazy JIT refresh, cached static values/adapters, and coalesced DEV9 host persistence. |
2026-07-29 01:36:47 +02:00
Brian Degenhardt 11865fe54b VMManager: delete the four dead arch #else bodies
Upstream guards these blocks with `#ifdef _M_X86 // TODO(Stenzek): Remove me
once EE/VU/IOP recs are added.` The arm64 JIT merge widened each guard to
`#if defined(_M_X86) || defined(ARCH_ARM64)` and left the `#else` bodies in
place, but Pcsx2Defs.h defines ARCH_X86 and ARCH_ARM64 exhaustively (anything
else is an #error) and _M_X86 is set on every x86 build -- by
BuildParameters.cmake for CMake and by common.props for MSVC. So none of the
four `#else` arms can compile on any supported target, and the recs upstream's
TODO was waiting on now exist. Collapsed all four.

Two of them were near-duplicates of the live branch carrying stale
Phase-4.3/6/7.8 commentary. The third, in ClearCPUExecutionCaches, is the one
worth naming: its dead body reset recCpu and psxRec unconditionally, with a
comment claiming that had to happen even when a rec is not the active
provider. It does not, and dropping it is not a behaviour change on top of it
already being unreachable -- ClearCPUExecutionCaches opens with
Cpu->Reset()/psxCpu->Reset(), and every path that can make a recompiler active
calls UpdateCPUImplementations() immediately followed by
ClearCPUExecutionCaches() (VM init, and Execute()'s interpreter/rec toggle),
so a rec is reset at the moment it becomes the active provider. x86 upstream
never resets a non-selected rec either.

No functional change on either arch. recompiler_tests 1443/1443.
2026-07-26 15:01:08 -07:00
Brian Degenhardt c2a4690474 VMManager: un-nest the ARM64 arm of the CPU extensions log
The `#ifdef ARCH_ARM64` sat inside the `#ifdef ARCH_X86` opened four lines
above it, so it could never compile and the whole "CPU Extensions Detected"
section was missing from every ARM log -- which is where we most want it.

Made it an `#elif`, and reported something worth reading while there. NEON
alone is architectural on AArch64 and therefore constant; what varies across
our targets is LSE (absent on the ARMv8.0 handhelds) and SVE, since SPU2
selects its SVE2 path at compile time and a mismatch there is the first thing
to check on a SIGILL report. cpuinfo_initialize() already runs unconditionally
in CPUThreadInitialize immediately before this call, so the predicates are
valid on ARM; only the early-hardware-check call site is x86-gated.

Verified on an M2 Max under Asahi: "NEON LSE CRC32".
2026-07-26 15:01:08 -07:00
jpolo1224 8a161bddc5 GS: age the texture pool every frame, and fix runtime GPU profile detection
AgePool() ran only on frames that actually presented, but it is what trims
the texture pool AND the only place GSDevice::m_frame advances. With
SkipDuplicateFrames on by default the pool could go a long time untrimmed,
grow to its limit, and push FetchSurface into handing back textures recycled
in the current frame. Reported as a slowdown in some scenes that cleared the
moment you changed any setting - that is not the setting, it is the settings
path calling PurgePool() and emptying a bloated pool.

m_runtime_gpu_profile defaulted to Adreno, so every backend that never called
SetRuntimeGPUProfile identified as Adreno: Vulkan, Metal and DX12 never called
it at all, and desktop OpenGL resolved anything not-Mali to Adreno. That fired
Adreno-only workarounds on Apple silicon (found by Brian Degenhardt) and left
IsMaliGPUProfile() permanently false under Vulkan, which silently disabled the
Tekken 5 MediaTek Mali GameDB fix on the renderer Android defaults to. Default
is Unknown now, Vulkan sets the resolved profile, and Apple has its own value.

Also: bound vkAcquireNextImageKHR instead of waiting forever on a destroyed
surface, rate-limit the synchronous pipeline-cache write, restore the manual
frame-skip and present-FPS-cap readers with an OSD indicator, widen the
decompressed-chunk cache from 2 so CHD streaming stops re-decompressing, and
stop InvalidateContainedTargets asking for a rect that cannot exist.
2026-07-26 02:01:27 -04:00
jpolo1224 069f8a44f3 Android 2.6.5.1: Local Link LAN play, async GS readback, pause/rotation/settings fixes
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.
2026-07-25 00:48:56 -04:00
Brandon eb61611b9d iOS: JIT Keep Alive fixes, Dynamic Backgrounds and UI performance improvements, New features Dynamic Controls, presets, efficient background lifecycle and Emulation-Only Mode.
iOS: JIT Keep Alive fixes, Dynamic Backgrounds and UI performance improvements, New features Dynamic Controls, presets, efficient background lifecycle and Emulation-Only Mode.
2026-07-24 22:52:00 +02:00
jpolo1224 8e23439b26 Android 2.6.5: Adreno Vulkan default, low-latency default, UI sounds, RA client hardening, GameDB
Rendering
- Auto renderer now resolves to Vulkan HW on Adreno (OpenGL elsewhere).
- Mobile hardware ROV (Phase 0): tile-native depth feedback behind the ROV toggle.

Performance & input
- Low Latency frame pacing is the default on capable devices, with a one-time
  migration for existing installs; low-end devices keep the queued pacing.
- Reduce Android input latency and improve input handling (PR #403, Splaser).
- Experimental CPU clock hint (ADPF) toggle in Performance settings (default off).

Audio & UI
- Pop-up open/close sound cues (info, hardcore confirm, patches & cheats).
- Alternating controller navigation / slider tick sounds.

RetroAchievements
- Inject the RA client version from a build-time secret kept out of public source,
  with a stock-PCSX2 fallback (no hardcore) for secret-less builds. Applies to the
  iOS client token too. Prevents third parties from copying our User-Agent.

Game compatibility
- Delta Force: Black Hawk Down (SLUS-21124 / SLES-53299) GameDB fixes
  (PR #401, XDarkFallenX).
2026-07-24 02:40:17 -04:00
Brian Degenhardt 2e9762d1d6 Rebrand user-facing PCSX2 references to ARMSX2; fix Help menu
Help menu (Linux desktop and everywhere):
- GitHub Repository pointed at a dead branch (/tree/macOS); now the repo root.
- Removed the PCSX2 Wiki and Documentation items (they linked pcsx2.net /
  wiki.pcsx2.net, impersonating upstream) and replaced them with a single
  ARMSX2 Website item pointing at armsx2.net.
- Removed Check for Updates (the auto-updater is disabled, so it only ever
  errored) and About Qt.
- About dialog body reworded to describe ARMSX2 (crediting PCSX2 as upstream).

Wrong-destination / impersonation fixes:
- PINE MsgVersion reply now identifies as "ARMSX2" (buffer sized accordingly).
- Bug-report links (GS unknown-video-mode / invalid-lod, EE COP2 warnings) now
  point at github.com/ARMSX2/ARMSX2/issues.
- "download a fresh copy" recovery messages (VMManager, SaveState, Windows
  updater, Win32 update-not-supported dialog) now point at armsx2.net.
- Auto-updater release/compare endpoints and staging-dir name de-PCSX2'd.

UI strings: setup wizard, cover downloader, and the Settings widgets (Qt) plus
their Big-Picture/Fullscreen ImGui twins now say ARMSX2. The "PCSX2Blue" theme
settings key is left unchanged (persisted / matched in code); only its display
name changes.

Interop identifiers deliberately left as-is: the PINE socket name (pcsx2.sock,
for PINE-client compatibility) and the RetroAchievements client name.
2026-07-23 19:48:13 -07:00
Brian Degenhardt 3e077eff9b Merge yaps2: arm64 JIT transplant + test/perf/libretro infrastructure
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.
2026-07-19 10:24:29 -07:00
J1coding 818a513e95 iOS: Skip RetroAchievements re-initialization when already active
VMManager::Internal::CPUThreadInitialize() can run more than once in
a process lifetime on mobile hosts that tear down and rebuild the CPU
thread across game launches. Achievements::Initialize() asserts
`!s_client && !s_http_downloader` at the top, so a second call with
RetroAchievements enabled fired pxFailRel("No client and downloader")
and aborted the process. The crash only manifested on hosts that
re-enter CPUThreadInitialize without an intervening Achievements
shutdown, which is why desktop builds never hit it.

Gate the call with !Achievements::IsActive(), which checks the same
s_client pointer the assertion reasons about. The normal cold-start
path (s_client == nullptr) still calls Initialize(); a second entry
with the client already constructed is now a no-op, matching the
expectation the rest of the file already has.

Verified by repeated launch/exit/relaunch cycles on iOS with
RetroAchievements enabled: no abort, and the client initialises
exactly once per process.
2026-07-18 17:45:52 +02:00
Jeen 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.
2026-07-12 16:39:22 +02:00
Jeen 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.
2026-07-12 16:38:59 +02:00
Jeen 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.
2026-07-12 16:38:18 +02:00
jpolo1224 d01b94d055 Recover mono ui-overhaul (PR#3 base + session UI edits) + prebuilt native .so from vc1063 2026-07-11 08:35:55 -04:00
jpolo1224 ed3cd1eed8 Android: re-apply mobile GS (VK push-descriptor fallback + GLES) onto canonical, guarded
Re-apply the Android-specific GS deltas on top of the canonical GS as guarded hunks so
PC/mac/Linux/Windows stay byte-for-canonical:

- VK: restore the push-descriptor fallback (Adreno/Mali stall inside
  vkCmdPushDescriptorSetKHR -> textures never bind -> black screen) as a capability-gated
  path; desktop keeps push descriptors unchanged. Mobile vendor gates
  (Mali/Adreno/PowerVR/Xclipse), dyn_shaderc, FIFO_RELAXED present mode, PowerVR swapchain
  width-align. depth_feedback forced off only under #if __ANDROID__ (desktop keeps
  feedback_loops()).
- OGL: re-apply GLES support (EGL context, is_gles shader branches, GLES query objects),
  runtime-gated by is_gles; guard 3 desktop-reachable riders (present-path
  glInvalidateFramebuffer -> is_gles, EGL SetDisplay body -> #if __ANDROID__, restore the
  negative-swap-interval probe).
- RA toast: guard the AddRect call on IMGUI_VERSION_NUM (desktop imgui 1.92.8 swapped the
  thickness/flags args; Android vendors 1.92.6) so the toast border renders on both.
- Suppress the 'Graphics API is not set to Automatic' OSD warning on Android
  (#if !__ANDROID__); desktop keeps the canonical warning.
- REFACTOR_STATUS: mark the GS re-apply resolved; note the imgui two-copies version skew.
2026-07-10 16:52:26 -04:00
David IsztlandClaude Opus 4.8 f3ef1105af core: back out unguarded desktop regressions from the parity graft
Three shared-core behavioral changes rode into PC unguarded via ecfebfd6b2 and are
reverted to canonical; the genuinely Android-only pieces around them (force-float +
nice-priority in VMManager, guarded #if __ANDROID__) are kept:

  * MTVU: WaitForWork() -> WaitForWorkWithSpin() spin-wait swap (all platforms)
  * VMManager: removal of the 'Graphics API is not set to Automatic' OSD warning
  * VMManager: s_thread_affinities_set tracked new_pin_enable instead of the
    canonical EmuConfig.EnableThreadPinning (desktop pinning-flag behavior)

Kept as legitimate additive/guarded shared changes: the new ThreadHandle API
(SetNicePriority/GetAffinity/GetCurrentCpu) + semaphore cache-line alignment, the
GetThreadPlacementDebug helper, Oboe/SoC-name/OSD-label Android features, and the
armsx2_overrides.yaml GameDB loader (PC-safe; no override file shipped).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 19:21:58 +02:00