Commit Graph
233 Commits
Author SHA1 Message Date
Henrik RydgårdandClaude Opus 5.5 8d62ae04dd Savestate: Make verify compare memory without emuhacks, and not count
The write pass stores memory with the JIT's emuhacks cleared, but the
verify pass compared against memory that still had them, so it would
report a mismatch under a JIT. Only EMULATOR_DEVCTL__VERIFY_STATE runs it,
and nothing currently does. It also counted as a save in the generation.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-28 09:36:47 -06:00
Henrik RydgårdandClaude Opus 5.5 937c100af8 Savestate: Defer operations while the GE debugger holds a list
The list belongs to the sceGe call still in progress, whose end would have
run on the loaded CPU state. Also stop the camera and GPS when a state has
them off, don't restart capture when saving, and fix a double free of the
pmp frame queue (it only holds the media engine's own frame).

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-28 09:34:06 -06:00
Henrik RydgårdandClaude Opus 5.5 db071361b0 Savestate: Wait for the SAS and IO threads before touching memory
Both drained only in their own DoState, after memory and Atrac contexts
had already been replaced under a mix or read still in flight. Also fix
sceUmd loading umdActivated into the wrong variable, and count each save
once in saveStateGeneration (it also bumped in the measuring pass).

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-28 09:34:05 -06:00
Henrik RydgårdandClaude Opus 5.5 9e69c1f9aa Savedata: Keep the IO thread out of the dialog's state
Replaces the temporary fix that did the hidden modes' IO inside Update.

The IO thread read and wrote the dialog's request, display state and save
list, all shared with the emulator thread, which kept using them to draw the
dialog and reload the request from the game.

Now the IO thread works on its own copy of the request, its own SavedataParam
and directory names resolved up front, and shares nothing else with the
emulator thread but the (locked) file system, MemoryStick_FreeSpace's cached
use and sceChnnlsv's scratch buffer and kirk state, the last two now under
locks too. It still reads and writes the game's buffers directly, like a PSP's
utility threads and sceIoReadAsync do, so a savestate waits for it before it
saves or loads memory. Save
bookkeeping, the save indicator and display changes happen on the emulator
thread when the results are taken, and only the request fields the IO changed
are copied back, so a game's own edits in the meantime survive.

Hidden modes take the results at the next Update (or, with Host IO timing,
the first Update that finds them done). The visible dialogs keep drawing and
take them once the IO is done; save and load used to stall the emulator
thread for the whole operation. Savestates keep results that haven't been
taken yet.

When the results land in PSP memory doesn't matter to games, so
utility/savedata/filelist now only prints them once the utility has finished.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-25 12:50:39 -06:00
Henrik RydgårdandClaude Opus 5 6600d1c05f Savestate browser: delete the screenshot and name file along with the state
Deleting a savestate from the savedata screen goes through GameInfo::Delete,
not SaveState::DeleteSlot, and it only knew about the .jpg - so the slot's
.name.txt was left behind with nothing to belong to.

Rather than teach the UI the naming scheme a third time, SaveState now answers
what sits beside a state.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-09-12 13:58:20 -06:00
Henrik RydgårdandClaude Opus 5 55f53d4523 Savestate names: read from the cached listing, and tidy up the name files
GetSlotCustomName hit the disk for every slot each time the pause screen built
its views, almost always for a file that isn't there. Rescan's listing already
knows, and HasSaveInSlot - which gates whether the name is even shown - reads
the same map, so this can't hide a name the old code would have found.

SetSlotCustomName now rescans, so a rename is visible without depending on the
pause screen happening to rescan on its way back.

Also: clearing a name deletes the file instead of leaving an empty one behind,
and the extension is "name.txt" rather than plain "txt", so an unrelated
"<prefix>_<slot>.txt" in the savestate folder isn't read as a slot name.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-09-12 13:58:20 -06:00
lain 78a00399ab Allow to define and modify custom names for saved states 2026-09-12 13:58:20 -06:00
Henrik RydgårdandClaude Opus 5 7d14efc331 Say why a savestate is refused while online, instead of dropping it silently
Same problem as the hardcore checks: SaveState.cpp asked NetworkAllowSaveState()
and just returned, so a load or save refused because you're connected did
nothing at all, with no explanation. Switched all eight to
NetworkWarnUserIfOnlineAndCantSavestate(), which is the same predicate plus the
standard message; its OSD id already collapses duplicates for the paths that
check twice on the way in.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01GgACRqkQNpfJQ4fjwyoEup
2026-09-05 13:34:12 -06:00
Henrik RydgårdandClaude Opus 5 be834b4446 Ban freeze-frame in hardcore mode, and tell the user when a savestate is refused
Freeze-frame restores a savestate every frame, straight through
SaveState::LoadFromRam(), so it never touched the operation queue and neither
hardcore check saw it. Blocked at the toggle in the dev menu, and again in the
render loop, since hardcore mode can come up after the fact once the game has
been identified.

Enqueue also just dropped operations silently, so a load that arrived through a
path with no check of its own (--state, auto-load) did nothing with no
explanation. Both it and Process now go through WarnUserIfHardcoreModeActive,
which is the same predicate plus the standard message. Callers that already ask
it themselves return before reaching Enqueue, so nothing shows the message twice.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01GgACRqkQNpfJQ4fjwyoEup
2026-09-05 13:29:50 -06:00
Henrik RydgårdandClaude Opus 5 255896e89f Re-check hardcore mode when a savestate op is actually applied
The check lived only in Enqueue, but operations don't run there - they're
queued and applied later by Process(). During boot, HardcoreModeActive() reads
false even when hardcore is on, since it requires rc_client_is_processing_required(),
which only becomes true once RetroAchievements has finished identifying the game
asynchronously. Anything queued in that window passed the check, and was then
applied by Process() after identification completed and hardcore came up.

Auto-load wasn't even a race: EmuScreen::bootComplete() calls Achievements::SetGame(),
which starts the identify, and then checks HardcoreModeActive() a few lines below -
always false at that point. So "Auto load savestate" quietly worked in hardcore mode.
--state and a load-state hotkey pressed during boot got through the same way.

Re-checking per operation in Process() covers every entry point at once, and by
then identification has finished, so the answer is authoritative.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01GgACRqkQNpfJQ4fjwyoEup
2026-09-05 13:27:28 -06:00
Henrik Rydgård a49f4523cb Correct when we process the stepping queue. Also, the jitLock mutex is no longer needed. 2026-08-16 13:33:26 +02:00
Henrik Rydgård 58d4759ceb Add bounds checking to savestate deserialization
PointerWrap tracked no end-of-buffer, so DoState() implementations could
read past the end of a crafted or truncated savestate via DoVoid's
unchecked memcpy, and DoVector could resize to an attacker-controlled
size before reading.

- PointerWrap now tracks a read end; DoVoid/ExpectVoid fail (MODE_NOOP)
  before reading out of bounds.
- String reads are bounds-checked for the whole string including NUL.
- DoVector rejects sizes that can't fit in the remaining buffer.
- LoadPtr takes the buffer size and sets the read end.
- Capping the decompression buffer allocation in LoadFile.
2026-08-01 11:57:24 +02:00
Henrik Rydgård 07efc7f7a3 Buildfix, remove some .c_str() 2026-05-19 13:59:04 +02:00
Henrik Rydgård fb7ce84edb SaveState: Show time/date when loading states 2026-05-19 12:19:40 +02:00
Henrik Rydgård c20d20ccba Show timestamps when loading rewind states 2026-05-19 11:58:01 +02:00
Henrik Rydgård 231aefe476 Code cleanup for save state notification, add metadata field 2026-05-19 11:07:07 +02:00
Henrik Rydgård 412bbb268a SaveState: Fix memory bug (can't safely pass string_view into a lambda) 2026-02-19 11:07:48 +01:00
Henrik Rydgård 386fc442a6 Rework the internal screenshot API, fix bug causing screenshotting to get stuck 2026-02-13 12:34:26 +01:00
Henrik Rydgård 1599ea7b1d SaveState: Separate screenshot operations from other ops 2026-02-08 16:11:44 +01:00
Henrik Rydgård 188945f0fe Warning fixes 2026-01-19 17:56:30 +01:00
Henrik Rydgård f1f931551a Add a "Savestate slot count" setting. 2026-01-09 12:20:39 +01:00
Henrik Rydgård 884d3c46d5 Rework listing of savestates - a single scan operation instead of lots of File::Exists and ModTime calls.
Needed to improve scalability on Android for when we increase the number
of states.
2026-01-09 11:17:21 +01:00
Henrik Rydgård 2959ad214c Fix the internal savestate API to better reflect how it actually works 2026-01-09 10:29:37 +01:00
Henrik Rydgård e6e82c9ad3 Add java-side prefix filtering for ContentUri directory listing 2026-01-09 10:12:15 +01:00
Henrik Rydgård e33ff46ffd Extract the rewind code from SaveState.cpp, to make it more managable. 2026-01-08 22:22:46 +01:00
Henrik Rydgård 77b9a6e2e8 Prepare for adjustable save state slot count by making the Win32 menu dynamic 2026-01-08 16:07:48 +01:00
Henrik Rydgård f89c169f8a Use the correct ID when creating game configs from the pause screen 2025-09-04 11:34:55 +02:00
Henrik Rydgård 038f1a139e Implement save state deletion in the save state popup screen
Fixes #16223
2025-08-15 15:49:03 +02:00
Henrik Rydgård 9a86101769 Avoid getting stuck in a load-loop when auto-loading a bad savestate. Make some code clearer. 2025-05-16 01:55:18 +02:00
Henrik Rydgård a698486f9c Savestate: The callback is already an std::function, so no cbUserdata value is needed. 2025-05-16 01:55:15 +02:00
Henrik Rydgård 088a02bfdb Cleanup a lot of the bootup state management. 2025-03-30 14:02:29 +02:00
Henrik Rydgård 44bb7a1ac5 Buildfix, minor savestate fix 2025-03-21 20:45:12 +01:00
Henrik Rydgård b421c0791f Perform screenshot processing (including image encode) on background tasks 2025-03-20 20:48:51 +01:00
Henrik Rydgård 14ee85139d Remove unused ability to call callbacks after taking a savestate screenshot 2025-03-20 19:41:10 +01:00
Henrik Rydgård ae8f8c4abd Refactor TakeGameScreenshot a bit. 2025-03-20 17:41:44 +01:00
Henrik Rydgård 3ccd6d17c9 Reduce logspam from failed screenshots for savestates. Fixes #19946 2025-03-02 20:14:03 +01:00
Henrik Rydgård 31cf5771f4 Turn the break reason into an enum, fix some minor issues 2025-02-19 16:01:11 -06:00
Henrik Rydgård 9bee4192ba Implement exit confirmation when closing the window on Windows. 2025-02-17 13:09:11 -06:00
Henrik Rydgård 408d1b0916 Track execution time after save, add new setting for exit confirmation 2025-02-17 12:29:23 -06:00
Henrik Rydgård 5d124d93f8 Make network connection detection (for pause screen purposes) a bit more strict. 2025-01-21 12:22:29 +01:00
Henrik Rydgård f66ea2f63e Add a bunch of restrictions when online (no savestate, no speed control) 2025-01-13 19:33:48 +01:00
Henrik Rydgård 96c4a10e8c Add two new core states, rename RUNNING to RUNNING_CPU and similar for stepping. 2024-12-01 21:04:21 +01:00
Henrik Rydgård 4793222fae Optimize away a File::Exists when checking savestate dates 2024-11-30 00:36:05 +01:00
Henrik Rydgård 3a5968ba33 Don't block the render thread while the CPU is paused. This is a prereq for imgui debuggers. 2024-11-05 12:53:21 +01:00
Henrik Rydgård d3e9398cb3 Split Core_EnableStepping into Core_Break and Core_Resume 2024-11-03 17:53:42 +01:00
Henrik Rydgård b43abd2015 Fix issues with savestates and non-buffered rendering 2024-10-17 21:09:04 +02:00
Henrik Rydgård 858f37b8fc Add a couple of asserts (to make things error out earlier) 2024-10-17 21:01:58 +02:00
Henrik Rydgård e504973cf0 On load state failure, don't go off reloading another rewind state, unless we were actually rewinding. 2024-07-20 00:40:21 +02:00
Henrik Rydgård e01ca5b057 Logging API change (refactor) (#19324)
* Rename LogType to Log

* Explicitly use the Log:: enum when logging. Allows for autocomplete when editing.

* Mac/ARM64 buildfix

* Do the same with the hle result log macros

* Rename the log names to mixed case while at it.

* iOS buildfix

* Qt buildfix attempt, ARM32 buildfix
2024-07-14 14:42:59 +02:00
Henrik Rydgård d21fef52ae Allow taking screenshots in the app menu 2024-05-10 21:10:11 +02:00