190 Commits
Author SHA1 Message Date
Brian Degenhardt 08dddb0947 SaveState: add a reader for the legacy 0x9A2C/0x9A34 blob layouts
Savestates written by the AetherSX2/NetherSX2 era of upstream PCSX2 use two
internal-structures layouts that today's reader cannot parse: 0x9A2C (upstream
0312e902) and 0x9A34 (upstream 7e939b75). Add a load-only deserializer that
consumes those layouts field-by-field into live emulator state.

Old struct layouts are declared in an OldState namespace, each cited to the
upstream sha it was taken from and guarded by a static_assert of the byte-exact
size. A second assert group pins the sizes of the CURRENT types the legacy
layout depends on, so upstream drift breaks the build rather than desyncing a
load mid-blob. Blocks that are byte-identical across eras reuse the existing
freeze functions.

The two era gaps that need real work: 32-bit cycle counters widen relative to
their domain base so wrap-straddling deltas survive, and fields that moved
between the cpuRegs and Cycles blocks at 0x9A31 are staged and committed once,
after the disc identity check, so a wrong-game state cannot half-apply.

Not yet wired into the load path; that follows.
2026-08-02 11:19:56 -07:00
Brian Degenhardt 5bf499b21d SaveState: plumb the on-disk savestate version into the load path
CheckVersion now reports the version word it read, and
LoadInternalStructuresState forwards it into SaveStateBase::SetVersion,
so freeze readers can see the actual version of the file being loaded
instead of assuming g_SaveVersion. No behavior change: the version
gate itself is unchanged, and nothing consults the plumbed value yet.

Groundwork for loading legacy-format (AetherSX2-era) savestates.
2026-08-02 11:19:55 -07:00
WizzardSK e775870c2c libretro core frontend (yaps2_libretro.so): Vulkan context sharing, pacing, input, audio (#4)
* Libretro: Scaffold yaps2_libretro core (M1: builds + dlopens)

New pcsx2-libretro/ target producing yaps2_libretro.so (ENABLE_LIBRETRO=ON,
or built on demand). Milestone 1 of the libretro port:

- Full libretro v1 entry-point surface, version-script-restricted to
  retro_* exports (PCSX2 internals must not collide with the frontend).
- Host:: implementations adapted from pcsx2-sdl: same CPU-thread state
  machine (VMManager::Execute on a dedicated thread, RunOnCPUThread queue),
  no windowing/clipboard/file-picker.
- retro_load_game boots the VM headlessly: GS renderer forced to Null,
  Surfaceless WindowInfo, null audio; config+data self-contained under
  <system dir>/pcsx2 (yaps2-libretro.ini).
- retro_run presents a placeholder XRGB8888 frame; no pacing yet.
- POSITION_INDEPENDENT_CODE forced ON (the pcsx2-sdl ET_EXEC persisted-JIT
  trick cannot apply to a shared core).

Verified: builds in org.kde.Sdk 6.10 (gcc), dlopen + retro_api_version +
retro_get_system_info OK.

Next: M2 Vulkan negotiation interface (wrap vkCreateInstance/Device so
GSDeviceVK inits against the frontend-shared device, set_image handoff),
M3 frame pacing + libretro input/audio, M4 savestates/disk control.

* Libretro: M2 Vulkan context sharing + frame handoff (first light)

The lrps2-libretro pattern ported to the modern GSDeviceVK:

- VKLibretro.{h,cpp}: the loader's global vkGetInstanceProcAddr is swapped
  for a wrapper that intercepts vkCreateDevice (merges the frontend's
  required extensions/layers/features into GS's create info and captures
  the shared VkDevice) and vkQueueSubmit (serialises against the frontend
  through the HW-render interface queue lock).
- GSDeviceVK: adopts the negotiation-provided VkInstance/VkPhysicalDevice
  instead of creating its own (and never destroys the frontend's instance);
  the surfaceless BeginPresent branch publishes the merged display texture
  (ShaderReadOnly + ExecuteCommandBuffer) into a mutex-guarded slot.
- Main.cpp: RETRO_HW_CONTEXT_VULKAN + context negotiation interface
  (create_device opens MTGS from the frontend thread, so GSDeviceVK is
  fully constructed before the context reply); the VM boot parks until
  context_reset delivers the retro_hw_render_interface_vulkan; retro_run
  consumes at most one published frame per call and forwards it via
  set_image + video_cb(RETRO_HW_FRAME_BUFFER_VALID), dupe otherwise.

First light verified on Turnip Adreno 618 (and llvmpipe): GT3 boots
(VMManager::Initialize StartupSuccess), frames arrive hw_valid with a
non-black 640x448 readback.

Known gaps for M3: no frame pacing (VM free-runs; YAPS2_RUN_SLEEP=1 paces
headless runs), no libretro input/audio, m_current is sampled by the
frontend while GS may already be rendering the next frame (single
buffered), no OSD.

* Libretro: M3 frame pacing, joypad input, audio

- Pacing: PublishFrame now blocks the GS thread until retro_run consumes
  the frame (one presented frame per retro_run; the frontend's cadence is
  the emulation's vsync). Enabled at context_reset, aborted before any
  path that could otherwise leave the GS thread parked (context_destroy,
  retro_unload_game, VKLibretro::Shutdown). Static screens still dupe
  thanks to yaps2's SkipDuplicateFrames -- the VM keeps 100% speed and the
  frontend gets video_cb(NULL) for unchanged frames.
- Input: retro_run forwards the libretro joypad + both analogs straight
  into the DualShock2 bind slots (Pad::GetPad(0)->Set), bypassing
  InputManager; SDL input source stays disabled.
- Audio: AudioStream grows a public PullFrames() (frontend-driven pull
  from the ring), SPU2 exposes GetOutputStream(), the config pins the
  Null backend (mix into the ring, no device thread), and retro_run
  drains the ring into audio_batch_cb with float->s16 conversion.
- Config: EmuFolders::Settings is now set explicitly (the libretro path
  bypasses SetDataDirectory, so the INI used to land in the cwd).

Verified on Adreno 618 with GT3: internal fps 59.9, speed 100%, frames
publish on change, INI persists under <system>/pcsx2/inis.

* Libretro: Stable backbuffer ring + dynamic PAL av_info

Fixes the RetroArch heap-corruption crash ~2 minutes in (GT3 FMV -> demo
race transition): the published frame was the pooled m_current texture,
which GSDeviceVK recycles while the frontend still samples the view for
cached-frame replays. Frames are now copied into a dedicated ring of
three backbuffer textures owned outside the pool; on a resolution change
the displaced buffer is retired (kept alive until device teardown)
instead of destroyed, because the frontend can replay the old image
indefinitely (e.g. while its menu is open). Verified: headless harness
clean over 4+ minutes at ~100% speed, RetroArch session stable past the
previous crash point.

Also: when the booted VM reports a vertical frequency different from the
NTSC default (PAL 50Hz, progressive), retro_run pushes an updated
retro_system_av_info to the frontend.

* Libretro: M4 save states (retro_serialize/retro_unserialize)

SaveState grows in-memory zip variants sharing the existing disk code:
SaveState_ZipToBuffer writes the ArchiveEntryList into a libzip
buffer source (zip_source_keep + read-back after close), and
SaveState_UnzipFromBuffer opens one over the incoming blob; the whole
entry/version/screenshot pipeline is reused via a shared
SaveState_UnzipFromZip body, so the on-disk and in-memory formats are
identical (a retro state is a valid .p2s payload).

retro_serialize runs SaveState_DownloadState + ZipToBuffer as a blocking
RunOnCPUThread job with frame pacing temporarily disabled -- while the
frontend is inside retro_serialize it is not calling retro_run, so a
parked PublishFrame would deadlock the GS freeze. The fixed
retro_serialize_size bound is 68 MiB (DownloadState's 64 MiB working
buffer + slack); the actual zip length travels as a leading u64 inside
the block.

Verified on GT3 (Adreno 618): serialize 587 ms, unserialize 131 ms,
emulation continues cleanly after the in-place load.

* Libretro: M4 core options + disk control (m3u multi-disc)

Core options (RETRO_ENVIRONMENT_SET_VARIABLES): GS renderer
(Vulkan/Software; the software renderer still presents through the
shared Vulkan context, so the negotiation path is unchanged), internal
resolution 1x-4x (EmuCore/GS upscale_multiplier, live), fast boot and
widescreen patches. Startup values apply before LoadStartupSettings;
later changes re-apply via VMManager::ApplySettings on the CPU thread.

Disk control (SET_DISK_CONTROL_EXT_INTERFACE): .m3u playlists parse
into a disc list (relative entries resolved against the playlist dir),
single-disc content registers as a one-entry list, and closing the tray
swaps via VMManager::ChangeDisc on the CPU thread. m3u added to
valid_extensions.

Regression-tested on GT3: boot, savestate roundtrip and rendering
unchanged.

* Libretro: OSD via real present path into the backbuffer

The surfaceless BeginPresent no longer copies m_current and skips the
frame -- with the libretro context active it begins an actual present
render pass targeting the dedicated backbuffer (clear + viewport/scissor,
same sequence as the swapchain path) and returns PresentResult::OK. The
whole standard presentation pipeline now runs unchanged: PresentRect
draws the display aspect-corrected with TV shaders/linear filtering,
FullscreenUI::Render and ImGuiManager::RenderOSD draw the overlay, and
EndPresent (libretro branch) finishes the backbuffer, submits without
swapchain semantics and publishes the image to the frontend. The old
copy-based publish is gone.

New core option: yaps2_show_fps (EmuCore/GS OsdShowFPS).

Verified on GT3/Adreno 618: readback shows the ImGui FPS counter drawn
over the aspect-corrected frame; boot/savestate regression clean.

* Libretro: Fix retro_serialize bounds check to include the u64 length header

The check compared buffer.size() against the caller's buffer size, but the
write is sizeof(u64) + buffer.size() — a state within 8 bytes of the
reported serialize size would overflow the frontend's buffer.

* Libretro: Size the output canvas to the internal resolution

The present backbuffer was sized from the fixed 640x448 window info, so
the upscale option rendered internally at 2x-4x and then got scaled back
down before the frontend ever saw the frame.

The present path now tracks the merged frame: expand it to the target
aspect ratio (the internal-resolution screenshot rule), clamp it to the
advertised max geometry (2732x2048, 4x PAL at 4:3), and resize the
surfaceless "window" before the draw rect is computed so the whole
frame stays consistent. ResizeWindow learns to adopt a new size with no
swap chain, and retro_run reports geometry changes with SET_GEOMETRY so
the frontend keeps scaling correctly. Resizes are rare in practice (boot,
FMV/interlace switches, option changes) and reuse the existing
retire-don't-destroy backbuffer ring.

* Libretro: Core options v2 + video/performance options

Registers options through SET_CORE_OPTIONS_V2 with Video/Performance/
System categories and per-option help text (legacy SET_VARIABLES kept as
the fallback), and adds:

- Aspect ratio (Auto 4:3/3:2, 4:3, 16:9, Stretch) — the canvas sizing
  follows it, and 16:9 pairs with the widescreen patches option
- Deinterlacing mode (Automatic/Off/Weave/Bob/Blend/Adaptive)
- No-interlacing patches (progressive output for supported games)
- Blending accuracy (Minimum-Maximum)
- EE cycle rate (50%-300%) and EE cycle skip speed hacks

* Libretro: Don't double-load the Vulkan library in EnumerateGPUs

The frontend preloads libvulkan for the context negotiation, and
EnumerateGPUs asserted (and would have unloaded the host's library) when
called with no device open — which is exactly the Software renderer
path, via D3D::GetPreferredRenderer. Use the already-loaded library and
leave it loaded.

* Libretro: Second wave of core options

Video: texture filtering, anisotropic filtering, software renderer
threads. Performance: hardware download mode (readbacks are expensive
on tile-based mobile GPUs), MTVU and Instant VU1 toggles. System: BIOS
selection (scanned from <system>/pcsx2/bios at option registration,
auto = first valid image) and cheats (.pnach loading).

* Libretro: Fix crash on content close

Two shutdown bugs, both hit on every quit-from-menu:

- GSDeviceVK::Destroy destroyed the negotiated VkDevice, but that device
  belongs to the frontend (it made the vkCreateDevice call) and the
  frontend tears it down after context_destroy — RetroArch was left
  waiting on and destroying a dead device (freeze, then segfault).
  Guard it like the adopted VkInstance already was.

- The frontend replays the last set_image indefinitely (menu background,
  duped frames), so retro_unload_game now retracts the image and waits
  for the GPU before VM teardown destroys the textures it points at.

Verified: 6/6 clean RetroArch exits after a full Vulkan content run
(was a reliable SIGSEGV on close before).

* Libretro: Reclaim retired presentation backbuffers

A resolution change retires the displaced backbuffer instead of freeing
it, because the frontend may still be replaying its image for a few
cached/duped frames. But the retired list was only cleared at device
teardown, so every interlace<->progressive switch (frequent in FMV-heavy
games) leaked a full-resolution render target for the rest of the
session.

Each retired backbuffer is now tagged with a monotonic present count and
reclaimed once kLibretroRetireFrames (6) presents have gone by --
comfortably beyond any libretro frontend's swapchain depth (2-3), and
GSTextureVK destruction is itself fence-deferred, so the underlying
Vulkan objects aren't freed until the GPU is done with them either.

Verified: GT3 boots/renders through its 640x448<->640x480 interlace
switches with no crash (harness + real RetroArch, clean exit).

* Libretro: Move libretro headers to 3rdparty/libretro

The libretro Vulkan HW-render interface header was pulled in by adding
pcsx2-libretro/ to PCSX2_FLAGS's INTERFACE include path, which leaked
onto every target that consumes PCSX2_FLAGS (and had the GS backend
reaching into the frontend's source dir).

Move libretro.h + libretro_vulkan.h into 3rdparty/libretro/ behind a
header-only INTERFACE library (libretro-headers), and link it PRIVATE
to the two targets that actually need it: PCSX2 (for VKLibretro.cpp) and
the pcsx2-libretro frontend. No other target sees the headers now.
2026-07-13 10:56:30 -07:00
Ziemas f0723a6ec9 vu: 64bit cycle fixes
[SAVEVERSION+]
2026-03-15 08:27:44 -04:00
Ziemas f576962dd8 EE: Switch to 64 bit cycle counter
[SAVEVERSION+]
2026-03-07 09:28:55 -05:00
Ziemas 10fc9a790d SPU: Emulate voice decode buffers
This makes the timing of NAX advancing more similar to console since it
emulates the decode buffer behaviour of it rushing ahead of playback
until the buffer is full.

It also makes interpolation of the first four samples more correct by
using real data instead of the zero filled previous values.

[SAVEVERSION+]
2026-01-28 12:18:43 -05:00
Ziemas c42330eebf SPU: Remove unused voice struct members
Might as well If the saveversion is already being bumped.

[SAVEVERSION+]
2026-01-28 12:18:43 -05:00
SternXD d983b2b066 Copyright: Change year from 2002-2025 to 2002-2026 2026-01-15 00:22:32 +01:00
chaoticgd cf4412ecbe SaveState: Fix error handling in SaveState_ZipToDisk 2025-12-13 21:42:52 -05:00
chaoticgd e8c2cfa843 SaveState: Rework error handling when saving states 2025-12-13 21:42:52 -05:00
chaoticgd 764875ddbf Qt: Add setting to show state load errors using a dialog or OSD message 2025-12-13 21:42:52 -05:00
JordanTheToaster 68803229da Core: Bump savestate version.
[SAVEVERSION+]
2025-11-02 20:19:38 -05:00
lightningterror 50bc0193ac Core: Bump savestate version.
[SAVEVERSION+]
2025-06-02 01:30:50 +02:00
TheTechnician27 23fd57f641 Copyright: Change year from 2002-2024 to 2002-2025 2025-01-20 05:07:26 +01:00
Ty Lamontagne c513a29bcf EE Cache: Freeze cached entries in sstates
[SAVEVERSION+]
2024-12-27 14:18:32 -05:00
Ty Lamontagne a2c7542e48 Savestates: Warn on savestate load and saves without mcd activity
[SAVEVERSION+]
2024-12-18 18:01:30 -05:00
TheLastRar 4a04100207 [SAVEVERSION+] HostFS: Always write savestate tag 2024-11-28 15:47:52 -05:00
pips3 bba85dc08f HostFS: Retain File Handles in Save States
[SAVEVERSION+]
Save file handle information in save states, and reopen handles when states are loaded.
2024-10-07 09:56:31 -04:00
GovanifY 132431b7c8 headers: relicense to GPL-3.0+
also update to 2024 while i'm at it
2024-07-30 17:17:13 -04:00
Stenzek 7166c04ff2 R3000: Serialize IOP->EE ticks carry
[SAVEVERSION+]
2024-05-16 20:08:38 +10:00
refractionpcsx2 566ea8ea9b Core: Refactor a lot of timer work and fix a couple of bugs
EE/IOP Timers: improve clock sync, disable v/h sync when SINT enabled.

Some changes based on tests from PS2

[SAVEVERSION+]
2024-05-15 10:54:26 +01:00
Benjamin Moir 5f7e97c27c [SAVEVERSION+] EE: Expose advanced option for extra memory 2024-05-09 13:45:06 +10:00
refractionpcsx2 5f7c2b7cd8 EE/IOP Timers: Rewrote most of the gate handling to be better.
[SAVEVERSION+]
2024-04-29 17:25:51 +01:00
Stenzek fb15893521 VMManager: Remove and merge System.cpp 2023-12-27 13:55:35 +10:00
Stenzek d9abe10308 Misc: Remove explicit PCH include, switch to SPDX 2023-12-24 14:03:14 +10:00