Commit Graph
47870 Commits
Author SHA1 Message Date
Henrik RydgårdandClaude Opus 5.5 8661fbf8ce arm64 JIT: Compile vf2i, vsgn, vslt, vsge and vcmp EI/NI
These went to the interpreter. vf2in/vf2iz/vf2iu/vf2id use FCVT, which
saturates like the PSP, and patch NaN to 0x7FFFFFFF like the IR
backend. vsgn keeps the sign bit on 1.0 and gives 0 below the smallest
normal. vsge and vslt select 1 or 0 on a compare whose condition is
false when unordered. EI and NI test |s| against infinity in integers.
All match the interpreter on special values, ties and denormals.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 14:31:22 -06:00
Henrik Rydgård 319fbedabf Merge pull request #22346 from hrydgard/macosx-fixes
MacOSX: Menubar fixes, compile warning fix
2026-09-24 14:27:24 -06:00
Henrik Rydgård 19f57ec438 Merge pull request #22345 from hrydgard/use-vfpu-interpolator
Use the new VFPU special-function implementations globally
2026-09-24 14:27:09 -06:00
Henrik RydgårdandClaude Opus 5.5 ecf9efcf84 macOS: Add menu items from the Windows menu
Stop, Switch UMD, savestate slots, Load/Save State (Cmd+L/Cmd+S) and state
files, shortcuts to the settings screens (plus Settings... with Cmd+, in the
app menu), Rendering Resolution, Texture Filtering, Enable Sound, Enable
Cheats and the website links.

Menu items now carry their action and how to tell whether they're checked
or enabled as blocks, checked each time a menu is shown, instead of tags
matched up in menuNeedsUpdate. The Graphics menu becomes Game Settings,
as on Windows.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 14:03:15 -06:00
Henrik RydgårdandClaude Opus 5.5 48b380a27e macOS: Fix menu bar items
- Recent files always booted the first one (no item had its tag set), and
  the list was never refreshed. Rebuild it when opened, with the path on each item.
- The Graphics and Debug menus were never updated when opened: they were
  matched by title, looked up under different translation keys than they
  were created with. Compare the menus themselves.
- The Fullscreen item toggled bFullScreen twice, doing nothing.
- The status counter items checked their tag instead of the flag.
- Remove Restart Graphics from the Debug menu (it shared tag 12 with Show
  Debug Statistics).
- Drop @available checks for versions below the deployment target.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 13:40:56 -06:00
Henrik RydgårdandClaude Opus 5.5 b832ceab83 IR: Add FExp2 and FLog2 for vexp2, vlog2 and vrexp2
These were always interpreted. They're now IR ops that the native
backends compile to calls to vfpu_exp2 and vfpu_log2, like FSin and
FAsin. vrexp2 is FNeg followed by FExp2, which is how vfpu_rexp2
computes it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 13:34:19 -06:00
Henrik RydgårdandClaude Opus 5.5 d313cf7626 arm64 JIT: Call the exact VFPU sin, cos, asin, exp2 and log2 too
vsin, vcos, vnsin, vasin, vexp2, vlog2 and vrexp2 went to the
interpreter. They now take the same direct call as vrcp and friends.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 13:34:19 -06:00
Henrik RydgårdandClaude Opus 5.5 1f5f2f5ebb macOS: Target 11.0, the oldest current libc++ supports
With a deployment target of 10.13 (10.14 for arm64 libretro), every file
that includes a libc++ header warned "The selected platform is no longer
supported by libc++." Apple Silicon Macs start at 11 anyway.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 13:21:36 -06:00
Henrik RydgårdandClaude Opus 5.5 e932d55f1c Build: Only turn off floating-point contraction for CPU emulation
The vertex decoder's C++ steps may fuse, like the vertex JITs do; with
contraction off everywhere, RISC-V's VertexJit test found the JIT and
the steps disagreeing on morphed float UVs. The flag now applies to
Core/MIPS only, in CMake and the libretro Makefile. ndk-build has no
per-file flags, so the legacy Android.mk goes back to the default.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 12:59:04 -06:00
Henrik RydgårdandClaude Opus 5.5 9b4d4ee35b VFPU: Build sin, cos, asin, exp2 and log2 results as integer bits
A float made from a constant NaN bit pattern can come out quieted: MSVC
turned the 0x7F800001 that vcos, vexp2 and vlog2 return into 0x7FC00001,
which failed cpu/vfpu/exact on Windows. Each function now computes its
result's bits in integers and converts once at the end, like vrcp and
friends already did. Fixed-point results become floats by shifting,
which is exact since the VFPU keeps 22 significant bits. Identical to
the previous code over every 32-bit input.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 12:59:04 -06:00
Henrik RydgårdandClaude Opus 5.5 7ecdbe7799 UnitTest: Remove the old asin and sin/cos approximation experiments
They only printed comparisons against libm and checked nothing. The VFPU
functions are exact now and have their own tests.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 12:24:43 -06:00
Henrik RydgårdandClaude Opus 5.5 eeb48b35c5 x86 JIT: Sum vqmul's y and w in the interpreter's order
They were added in a different order, so they rounded differently from
every other backend.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 12:24:43 -06:00
Henrik RydgårdandClaude Opus 5.5 1206528e45 Build: Turn off floating-point contraction for C++
Clang and GCC fuse a * b + c into one rounding on CPUs that have fused
multiply-add, which on ARM64 made the interpreter's dot products, vavg,
vdet and vqmul round differently from x86-64. Fused operations now only
happen where the code asks for them. MSVC doesn't contract by default.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 12:24:43 -06:00
Henrik RydgårdandClaude Opus 5.5 b9144d4fca VFPU: Fold the result exponent into the rcp, rsqrt and sqrt coefficients
Each of the three is now a range check, a fast path and a few special
cases. The fast path reads its segment from a table whose constant term
already includes the result's exponent bits, so what remains is two
multiplies, some shifts and one exponent adjustment, all in integers.
Identical to the previous code over every 32-bit input.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 12:24:43 -06:00
Henrik RydgårdandClaude Opus 5.5 ba77f2259d Add cpu/vfpu/exact to tests_good
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 12:24:42 -06:00
Henrik RydgårdandClaude Opus 5.5 a2b10778be VFPU: vsqrt, vrsq, vrcp and vnrcp are exact in every backend
These went through the host's sqrt and division everywhere except the
interpreter's vrcp and vnrcp (vsqrt and vrsq there only behind
USE_VFPU_SQRT, now gone). They now always give the PSP's bits: the IR
gets FVSqrt (FSqrt stays the FPU's IEEE sqrt.s), and FRSqrt and FRecip,
which only the VFPU emits, become vfpu_rsqrt and vfpu_rcp; the IR
interpreter and the x64, arm64, RISC-V and LoongArch backends call them.
The old JITs call them directly, the ARM ones keeping the lanes in
callee-saved registers across the calls. cpu/vfpu/exact now passes on every core.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 12:24:42 -06:00
Henrik Rydgård 87ad32d578 Merge pull request #22344 from hrydgard/download-cancel-at-exit
Don't crash at exit with a download still in flight
2026-09-24 12:10:21 -06:00
Henrik RydgårdandClaude Opus 5.5 f20dd7565b Don't crash at exit with a download still in flight
A request started since the last RequestManager::Update (headless never
calls it) sat in newDownloads_, which CancelAll skipped. It was then
destroyed along with the static g_DownloadManager at exit, and its
destructor removed its progress bar from the already destroyed g_OSD:
"mutex lock failed". Seen with a Netconf dialog still downloading the
infra DNS json when a test ended.

CancelAll now takes the new ones too, and runs at shutdown while g_OSD is
still there. The Netconf json request is also let go of when the emulator
shuts down, rather than living on into the next game.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 11:23:59 -06:00
Henrik Rydgård 428c1a6aa6 Merge pull request #22343 from hrydgard/vfpu-interpolator
VFPU: Replace fp64's correction tables with accurate implementation of special functions
2026-09-24 10:46:33 -06:00
Henrik Rydgård f7af4c0d4e Merge pull request #22339 from hrydgard/sceutility-lifecycle
sceUtility lifecycle fixes, GameSharing placeholder, headless fixes
2026-09-24 10:29:28 -06:00
Henrik RydgårdandClaude Opus 5.5 d6b3d590eb VFPU: Compute log2, sin/cos and asin without correction tables, too
They use the same quadratic interpolator as rcp and friends, with three
twists. sin indexes the quarter wave from the top, and asin and sin work
in a per-segment exponent whose 4-ulp truncation also applies to results
in a lower binade. log2 truncates exponent + log2(1.m) toward zero to 22
significant bits, and where that step is coarser than 2^-24 the datapath
drops coefficient bits to match; that also covers the region just below
1.0 that needed a special case.

vfpu_sincos now reduces the angle once. With every table gone, so are
the asset folder, the loader, InitVFPU and the fallbacks for tables that
failed to load. All seven functions are bit-exact with the table-based
code over every 32-bit input.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 10:07:01 -06:00
Henrik RydgårdandClaude Opus 5.5 dade876474 VFPU: Compute vrcp, vrsq, vsqrt and vexp2 without correction tables
The four share one quadratic interpolator: 128 segments picked by the top
7 bits of the input, each with a constant, a linear and a squared-term
coefficient, and a squarer on the top 10 bits of the rest that rounds t^2
up to a multiple of 256. 128 small coefficient sets per function
replace the 1 MB of delta tables. Derived from the output of the
table-based code, and bit-exact with it over every 32-bit input.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 10:06:53 -06:00
Henrik RydgårdandClaude Opus 5.5 157b233865 Savedata: TEMP TEST FIX: Do the hidden modes' IO inside Update, not on a host thread
The IO thread wrote results (file lists, sizes, loaded data) straight into
PSP memory while the game kept running, so they landed at an arbitrary
point in its code. utility/savedata/filelist caught it now and then: a
poll saw the entries written but the counts still zero. On a PSP it's all
there when Update returns. Host IO timing still uses the thread.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 19:41:41 -06:00
Henrik RydgårdandClaude Opus 5.5 d4de590e3f sceCtrl: Name the port-taking buffer functions
sceCtrlPeek/ReadBufferPositive2/Negative2, which take a port before the
usual buffer and count. Not implemented.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 19:30:31 -06:00
Henrik RydgårdandClaude Opus 5.5 55e9862b90 libretro: Build PSPPlaceholderDialog
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 19:30:31 -06:00
Henrik RydgårdandClaude Opus 5.5 30fada5833 Utility: Run GameSharing through a placeholder dialog, quiet its WRONG_TYPE logs
GameSharing InitStart used to return 0 without starting anything, so its
GetStatus stayed at NONE and a game waiting for the dialog to finish
would hang. It now goes through the normal lifecycle (INIT, RUNNING,
FINISHED, SHUTDOWN, NONE) and reports that the user cancelled.

PSPPlaceholderDialog was abstract and unused (and missing from CMake);
it's now that stand-in.

WRONG_TYPE from GameSharing GetStatus/Update/ShutdownStart is what a PSP
returns whenever another dialog type was the last one started, so log it
at debug like the other dialogs. Sega Rally polls it every frame.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 19:25:24 -06:00
Henrik RydgårdandClaude Opus 5.5 5a23bb2d94 Savedata: Pick the crypt mode the way the firmware does
secureVersion and the key only matter for the full 1536-byte request; the
older sizes always save without a key. Otherwise SDK 2.07+ uses the new
keyed hash for versions 0 and 3, older SDKs the old keyed hash for 0 and
no key for 3, and version 2 is always the old keyed hash.

Versions 0, 2 and 3 all require a key, and are rejected with SAVE_PARAM
otherwise - including 0, which we used to save without a key. Matches the
SFO modes and save errors recorded in utility/savedata/secureversion; what
remains there is load strictness when secureVersion doesn't match the
file, which we keep lenient for older saves.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 19:25:24 -06:00
Henrik RydgårdandClaude Opus 5.5 ec00700730 Dialog: Fade in 200ms like the firmware, and accept input while fading in
On a PSP, dialog animations advance by animSpeed frames per Update and the
fades take about 200ms. Ours took 500ms (1/30 s per animSpeed, over
FADE_TIME 1.0), and all input was ignored until it finished, which made
dialogs feel sluggish, noticeably so in 30fps games. Input is still
ignored while fading out, once a choice has been made.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 19:25:24 -06:00
Henrik RydgårdandClaude Opus 5.5 cafbab50d9 Io: Reject memory stick paths with characters FAT can't store
sceIoOpen on such a path returns an invalid-argument error on hardware,
not file-not-found (utility/savedata/idlist).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 19:25:24 -06:00
Henrik RydgårdandClaude Opus 5.5 74c5cbf503 Savedata: Leave GetSize's needed strings alone when nothing is needed
Matches hardware; moves utility/savedata/getsize to tests_good.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 19:25:24 -06:00
Henrik RydgårdandClaude Opus 5.5 20970d5fad Dialog: Follow the firmware's thread priorities in init/shutdown
On a PSP, dialog init and shutdown happen partly at the accessThread
priority and partly at the graphicsThread priority, one phase after the
other. Model that with one helper thread that switches priority per phase,
and let starting it reschedule normally instead of disabling interrupts.

A caller with worse priority than both now sees shutdown complete inside
ShutdownStart, as on hardware. NFL Street 3 (graphics 17, access 19,
caller 111) calls the next InitStart right after ShutdownStart and used to
loop forever on 'A save request is already running' (#19957). The utility
pspautotests, where the caller has better priority, are unchanged.

Also logs the dialog thread priorities at debug level.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 19:25:24 -06:00
Henrik RydgårdandClaude Opus 5.5 24e44cb5dd CmdLine: Exit with an error on a bad option value
An invalid value (e.g. --debugger-run swallowing the next flag) printed an
error but returned Exit, so the process exited 0.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 19:25:24 -06:00
Henrik RydgårdandClaude Opus 5.5 a293221fe2 Headless: Default to software rendering again
Since 551e4cd0ab, headless without --graphics silently used the OpenGL
backend, since bSoftwareRendering defaulted to false. Under Mesa llvmpipe
on Linux/WSL, that hangs games early in boot (and test.py, which passes no
--graphics). The README already documents software as the default.

Also documents the traps hit while chasing this in docs/debugging.md.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 19:25:24 -06:00
Henrik Rydgård 09cf031f2b Merge pull request #22342 from hrydgard/vdot-neon
Accurate vdot: NEON and SSE2 implementations
2026-09-23 19:24:16 -06:00
Henrik Rydgård f65598c60f Merge pull request #22341 from sum2012/gpu-readback
Add ForceEnableGPUReadback compat By Gemini
2026-09-23 09:02:45 -06:00
Henrik RydgårdandClaude Opus 5.5 0ac12b7bf3 VFPUDot: Cover sums that round into the next power of two
A sum just below a power of two can round up into the next exponent, and
at the top of the range into inf; random inputs almost never land there.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 08:18:25 -06:00
Henrik RydgårdandClaude Opus 5.5 cd005b9041 VFPU: SSE2 version of the exact vdot
Same shape as the NEON one, which now shares its rounding tail. SSE2 has
no per-lane shift, so the alignment shift is a multiply by a power of two
built from float bits and converted by truncation; the unsigned maxima
use the 16-bit instructions, since every value involved fits in 15 bits.
Nothing depends on the host rounding mode or flush-to-zero.

Checked against the reference by VFPUDot and on 300M more inputs offline,
also with MXCSR set to round toward zero with FTZ and DAZ.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 08:18:25 -06:00
Henrik RydgårdandClaude Opus 5.5 649561764d VFPU: NEON version of the exact vdot
The four lanes are computed together: exponents, 24x24-bit products with
round-to-odd, alignment by truncation and a signed horizontal sum. One
pairwise maximum finds both the alignment exponent and any inf or NaN,
which go to the reference. The final rounding is branch-free and in
integers, since the host rounding mode may be the game's.

About three times the throughput of the reference on Apple M-series
(5.2 vs 15.2 ns per call). VFPUDot checks it against the reference on
four million inputs picked to cover cancellation, ties, subnormals and
the overflow edges; a billion more matched offline.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 08:18:25 -06:00
sum2012 a8b85eec8b Add ForceEnableGPUReadback compat
To solve gpu readback issue
2026-09-23 22:06:28 +08:00
Henrik Rydgård fa583d1d33 Merge pull request #22340 from sashwatpuri/fix/audio-file-duration-limit
Limit achievement sound effect duration
2026-09-22 21:39:19 -06:00
Sashwat Puri Sachde 805b9032e3 Limit achievement sound effect duration 2026-09-23 04:40:49 +05:30
Henrik Rydgård 7c18ad3d1e Merge pull request #22338 from hrydgard/video-texture-hash
Video texture tracking and avoiding hashing
2026-09-22 16:50:34 -06:00
Henrik Rydgård 818c08be4c Merge pull request #22337 from hrydgard/cpu-test-holes
Claude with pspautotests: CPU test holes
2026-09-22 16:19:17 -06:00
Henrik RydgårdandClaude Opus 5 772f4f6e7a AGENTS.md: note that headless needs the app's memstick for firmware runs
Without --memstick, a library whose HLE the config has disabled has no firmware
to resolve against, and the game dies on unresolved imports rather than falling
back to our HLE. The run still logs happily for its whole timeout, so the only
tell is zero flips.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-22 16:10:52 -06:00
Henrik RydgårdandClaude Opus 5 4aef060293 Carry "this is video" across block copies
videos_ only learns about the CSC output, so the texture we actually draw is
just an ordinary 512x512 8888 texture whose contents happen to be different
every frame: hash, miss, throw it in the secondary cache, rebuild, forever.

So track the copy. NotifyVideoCopy marks the destination as video when the
source is, and the copy funnels call it: sceDmacMemcpy, sceKernelMemcpy, and
the four replaced memcpy/memmove variants. It sits outside their "is either
side VRAM" gate, since a RAM-to-RAM copy of a frame is still a frame.

Being a video texture also gets it forced linear filtering and keeps it out of
texture upscaling, which is what you want for a video either way.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-22 16:10:28 -06:00
Henrik RydgårdandClaude Opus 5 aa7b1de28c Drop the texture replacer's "video" option
A `video = true` in textures.ini opted a pack into replacing and dumping video
textures. Both halves are a bad deal. Dumping writes a file per decoded frame,
which fills a disk rather than producing anything a pack can use, and replacing
means a hash lookup on content that is different every frame and will never be
found twice.

It was also the only reason the texture cache still hashed video textures at
all, so it cost every game that has ever played a cutscene, not just the packs
that set it.

Video textures are now never replaced and never dumped, and skipHash is simply
isVideo. An existing ini keeping the key is harmless - unknown options are
ignored.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-22 16:10:16 -06:00
Henrik RydgårdandClaude Opus 5 14bfd332dc Stop stacking duplicate video entries, and stop hashing video textures
NotifyWriteFormattedFromMemory appends to videos_ unconditionally. A game
blitting its decoded frame to the display buffer does that every displayed
frame while it waits for the next one to decode, so the same two or three
addresses come back over and over: Death Jr pushes 733 entries where there are
two distinct buffers, Tekken 6 around 53,000 where there are three. IsVideo()
walks that vector linearly on every texture. Refresh the matching entry instead
of appending a new one - Death Jr now holds 2 entries and Tekken 6 holds 18,
peak size 2 and 3.

The other half is the two TODOs that were already sitting there. A video
texture is new every frame by definition, so re-hashing it only confirms what
the VIDEO flag already said, and the secondary cache has nothing to offer a
frame that will never recur. Skip both, and with them the secondary lookup that
would otherwise key off a hash we no longer compute.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-22 16:10:00 -06:00
Henrik RydgårdandClaude Fable 5.1 43255afe9f test.py: cpu/fpu/roundmode is a known failure on riscv64
The ISA returns the canonical NaN from every operation, so a negative or
signaling NaN operand loses its sign and payload where the PSP keeps them.
Not worth a check per FP op in the JIT.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 15:04:05 -06:00
Henrik RydgårdandClaude Fable 5.1 5d35425acd Add cpu/fpu/roundmode, fpu_branch and cpu/lsu/llsc to tests_good
fpu_branch_hazard (the compare-to-branch hazard), cacheop (the write-back
data cache seen through the uncached mirror) and fpu_nan (which NaN 0/0
makes, host dependent on x86) go to tests_next. cpu/fpu/fpu is re-recorded
from a binary built with the current toolchain, which prints -nan.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 14:25:42 -06:00
Henrik RydgårdandClaude Fable 5.1 2d14cad065 FPU: sqrt.s of a negative gives the PSP's positive NaN
x86 (SQRTSS and libm alike) returns 0xffc00000 for it, the PSP 0x7fc00000.
-0 stays -0 and a NaN input comes through as it is, so only a negative
input needs the sign cleared: a compare and an xor in the x64 JITs, a
branch in the interpreters. cpu/fpu/roundmode.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 14:25:41 -06:00