Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Savestates #10478

Merged
merged 3 commits into from
Jul 4, 2022
Merged

Savestates #10478

merged 3 commits into from
Jul 4, 2022

Conversation

elad335
Copy link
Contributor

@elad335 elad335 commented Jun 19, 2021

Restrictions (most will be lifted as this work progresses):

  • Select libvdec.sprx in firmware libraries setting. (advanced tab) (well now it simply won't allow saving if HLE libvdec data is loaded in the background)
  • WCB+force CPU blit may improve compatibility.
  • PSN/Network - Offline.
  • Don't savestate while a message/save dialog is shown.
  • Do not save when the game itself is saving or installing game data (applies to disc games).
  • Do not delete or move game files.
  • Do not erase /dev_hdd1 contents.
  • Sharing savestates between people is not supported.
  • Do not HLE lwmutex or firmware libraries that aren't HLE'd by default. (the opposite is allowed as long as it's compatible with the game)

How to savestate

Ctrl+S savestates, savestate will be bootable from the game context menu later.

Versioning System

Because RPCS3 is one of the most complex emulators ever made (if not the most complex) and it is still in rapid development state, the need to update the emulation every now and then in a way which will affect savestates is inevitable.
So, while the rest of the emulators use a global version for their savestate for all components of the emulation, RPCS3 savestates will work in a smarter way which allows both rapid development of the emulation and high compatibility of old savestates.
The following actions has been taken:

  • Individual components of the emulation will use individual pair of "current" version and "supported" versions: what this means?
    "supported" versions are versions listed which are known to be compatible with current RPCS3 build. Code can support more than one version at a time! how? this is where "current" version kicks in, the "current" version is read from the savestate file itself and by its value the code knows how to use the savestates file.
  • Not all emulation components are being used all the time. When updating the emulation for let's say X component, savestates which do not make use of this X component will still be compatible. (take for example PSN features)
    In case the component is unused, its version won't even be saved to the savestate file!

Savestates modes (config.yml exclusives at the moment)

  • "Start Paused": When true, the emulation will be paused after first frame is being rendered. (note that this actually runs the emulation up to the next frame for it only then pauses it)
    This setting is currently off by default but let me know if you want it on by default!
  • "Suspend Emulation Savestate Mode": Savestates use does not have to enforce cheating-alike attidude! When this mode is on, emulation exits when saving and the savestate file is deleted after loading it. This mode is like hibernation of emulation, if you don't want your exprience of hard games to be ruined by savestates, consider use this mode! This mode is extremely size-efficient because HDD1 is not saved. (filesystem state is assumed to not change in this mode)
  • Experimental and unused yet: "Inspection Mode Savestates": This mode is meant for debugging, it allows the saved savestate to be loaded without any game files in order to view the threads/memory state. It will not allow starting the emulation from that point.

Additional TODO list: (besides lifting restrictions)

  • Multi-savestates slots, currently each game ID has only one savestate slot at path rpcs3/savestates/[TITLE ID].SAVESTAT
    If you want to simulate multiple slots, you can move and restore the savestate file at that path, or you can load savestate files directly via main RPCS3 context menu.

Fixes #4218

@elad335
Copy link
Contributor Author

elad335 commented Jun 20, 2021

Please test extensively this and report issues with logs. Also if you can get callstack for crashes I'll be glad. Issues remain unreported may persist after the pull requerst has been merged so please report them!

@elad335
Copy link
Contributor Author

elad335 commented Jun 20, 2021

Also feedback about reqeusted features is more than welcome!

@elad335
Copy link
Contributor Author

elad335 commented Jun 20, 2021

Also: before you are saving state, pause the emulation, go to kernel explorer and capture its contents. This really helps with debugging!
Utilities -> Kernel Explorer

@elad335 elad335 force-pushed the savestates branch 2 times, most recently from 791859a to 321e4a8 Compare June 20, 2021 08:48
@elad335
Copy link
Contributor Author

elad335 commented Jun 20, 2021

I just made kernel explorer always expand its entries and made it larger for ease of capture. (shared memory and lwmutex you can leave uncaptured if they are too large)

@elad335
Copy link
Contributor Author

elad335 commented Jun 20, 2021

I recommend capturing kernel explorer in video at 1fps so its contents can be easily read.

@Satan86
Copy link

Satan86 commented Jun 20, 2021

GT5 - Saved state, game continued playing fine. Finished the race I was currently on and moved on to the next in a different track, where it desynced. Loaded the savestate I had done in the previous race and the emulator crashed.
Log: RPCS3.zip
Savestate file: https://drive.google.com/file/d/1oRKGorzNktKDKo63RyLW8SDeqXWAmWMK/view?usp=sharing

Motorstorm - After saving state, the game crashed when reloading.
Log: RPCS3.zip
Savestate file: https://drive.google.com/file/d/1OeLsJzNTxjyfK9e3Q-gawIsgLEkxa-pj/view?usp=sharing

Motorstorm Apocalypse - Saved state, when the game finished reloading the entire emulator closed.
Log (last run): RPCS3.zip
Savestate file: https://drive.google.com/file/d/1Ziw7z9eAts_wjO4KPBk8clCH9S9vEknb/view?usp=sharing

Ridge Racer 7 - Saved state, when the game finished reloading it threw a fatal error.
Log: RPCS3.zip
Savestate file: https://drive.google.com/file/d/1HykRMEDZfTf5JXqpsdSmZnzDikdVy7t8/view?usp=sharing

Gran Turismo HD Concept - This game never worked in any savestate version, still a white screen when when reloading the game after saving state. Resuming the game after pausing freezes it, so the kernel explorer video was captured with the game running.
Log: RPCS3.log.gz
Savestate file: https://drive.google.com/file/d/1Sz-ZJ6INCs8n_bcPuKrrZFrnT6-_J0KW/view?usp=sharing
Kernel Explorer video:

2021-06-20.10-28-55.mp4

Skate 3 - Saved state, when the game finished reloading it threw a fatal error.
Log: RPCS3.zip
Savestate file: https://drive.google.com/file/d/197Mo_Xmpw7uRpw8yEHQ_1_ZZBK7KNiTF/view?usp=sharing
Kernel explorer video:

2021-06-20.10-47-03.mp4

God of War 3 - Everything seems to work fine, except performance took a hit after saving state, lost about 5 FPS.
Log (tested Heavenly Sword on the same run so it's also logged, it worked fine): RPCS3.zip
Savestate file: https://drive.google.com/file/d/1sKvunZp9ng7J5846626FMnwK0BHL7MEB/view?usp=sharing
Kernel Explorer video:

2021-06-20.11-14-02.mp4

The Last Of Us - Saved state, when the game finished reloading it threw a fatal error.
Log: RPCS3.log.gz
Savestate file: https://drive.google.com/file/d/1DlK6FvfHXuLMBJCJfW9FJHIQr-JjcqdJ/view?usp=sharing
Kernel Explorer video:

2021-06-20.11-33-27.mp4

I could get kernel explorer clips for the first few later if needed, they were tested before your latest commits

@ChrisNonyminus
Copy link

Grand Theft Auto IV (NPUB30702) crashes rpcs3 when loading states.
Tested on the opening of the game.
Log: RPCS3.log
Savestate File: https://drive.google.com/file/d/1b8aKQRzu-K8Hy8Qlb7giTgQw9kZvFayy/view?usp=sharing
Like a dummy, I forgot to record the kernel explorer before saving the state, so unfortunately I can't show any video of it because there is none.


Fallout New Vegas (BLUS30500) freezes when loading states.
Tested on the opening of the game, in-game, where you wake up in Doc Mitchell's house.
Log: RPCS3.log
Savestate File: https://drive.google.com/file/d/1406Zk_Bp9C6snGUH0qP-J0qD0usuTKZz/view?usp=sharing
Turns out RPCS3 crashes when starting the kernel explorer (for this game, at least), so I could record it for this, either.

@ChrisNonyminus
Copy link

Half Life 2 The Orange Box (BLUS30055) crashes rpcs3 when saving states, before the file is even made.
Tested in the opening of Half Life 2.
Log: RPCS3.log

@Jonathan44062
Copy link

Sonic Unleashed - Doesn't work with the save state and I got an error
Log:
RPCS3.log.gz
Savestate file: https://www.mediafire.com/file/axjk1j6tu2k8vc1/BLUS30244.SAVESTAT/file
Kernel Explorer Video:
https://www.youtube.com/watch?v=0HvW2z9M4Ps

@AphelionWasTaken
Copy link

AphelionWasTaken commented Jun 20, 2021

FFX Remaster - creating or loading a savestate causes the ground to render improperly. It appears black except for where characters are standing. No other observed issues.
image
image
RPCS3 FFX.log.gz
https://user-images.githubusercontent.com/61633628/122690063-d3c01500-d1ec-11eb-8914-1dc3589f3116.mp4

Rainbow 6 Vegas 2 - No observed issues.
RPCS3 Vegas.log.gz
https://user-images.githubusercontent.com/61633628/122690228-e5ee8300-d1ed-11eb-8ccb-a4befb679ed3.mp4

Tales of Xillia 2 - No observed issues.
RPCS3 Xillia 2.log.gz
https://user-images.githubusercontent.com/61633628/122689930-b63e7b80-d1eb-11eb-92bf-a761d9cca1d9.mp4

SSX - Creating or loading a savestate causes a graphical issue with the snow around your character. This issue does go away after a short amount of time.

Attempting to create a savestate after restarting a drop causes the emulator to crash. It fails to create a savestate in this situation.
image
image
Log (successful savestate)
RPCS3 SSX.log.gz
Kernel Explorer (successful savestate)
https://user-images.githubusercontent.com/61633628/122689671-25b36b80-d1ea-11eb-96bc-1b791daec4b1.mp4
Log (crash)
RPCS3 SSX Crash.log
Kernel Explorer (crash)
https://user-images.githubusercontent.com/61633628/122690670-93629600-d1f0-11eb-87fb-65a9ace98ba0.mp4

Haze - No observed issues.
RPCS3.log.gz
https://user-images.githubusercontent.com/61633628/122689536-e3d5f580-d1e8-11eb-9ed2-7908c2c933f5.mp4

Skate 2 - Creating a savestate crashes the emulator while the game reloads. Attempting to load this savestate also causes the emulator to crash while the game boots.
RPCS3 Skate 2.zip
https://user-images.githubusercontent.com/61633628/122691153-83988100-d1f3-11eb-804c-902575b25f3b.mp4

@Crafty-The-Fox
Copy link

DJ Hero 2 Demo - Creating a savestate crashes the emulator while the game reloads.

RPCS3 DJ Hero 2 Demo.zip

2021-06-20.20-51-45-1.mp4

@elad335
Copy link
Contributor Author

elad335 commented Jun 21, 2021

Anyone has visual studio and can get me callstacks for crashes?

@Megamouse Megamouse added the Savestates Anything that involves savestates label Jun 21, 2021
@Satan86
Copy link

Satan86 commented Jun 21, 2021

RPCS3 crashes whenever I try to boot a game with VS attached, no idea why. Will have to figure that out first

@elad335
Copy link
Contributor Author

elad335 commented Jun 22, 2021

You need to disable "break when this exception type is thrown" for RSX access violations to work.

@Satan86
Copy link

Satan86 commented Jun 22, 2021

Thanks for the suggestion, VS debugger is working. Got some callstacks:

Loading savestates on Motorstorm

Screenshot_7

Loading savestates on Ridge Racer 7

Screenshot_8

Loading savestates on Gran Turismo 5

Screenshot_10

Loading savestates on The Last Of Us

Screenshot_11

Loading savestates on Skate 3

Screenshot_12

Loading savestates on Motorstorm Apocalypse

Screenshot_13

@elad335 elad335 force-pushed the savestates branch 5 times, most recently from 5cd1a5d to c9804f0 Compare June 24, 2021 11:33
@elad335
Copy link
Contributor Author

elad335 commented Jun 24, 2021

Fixed UNIX builds, added debugging info for crashes.

@elad335 elad335 force-pushed the savestates branch 3 times, most recently from 95014d6 to 4d6e935 Compare June 24, 2021 16:21
@elad335 elad335 force-pushed the savestates branch 5 times, most recently from 3cb80e0 to f1a3716 Compare June 28, 2022 15:14
@kd-11 kd-11 self-requested a review June 28, 2022 16:04
@elad335 elad335 force-pushed the savestates branch 3 times, most recently from 82b56b7 to 055820a Compare June 28, 2022 17:12
thread_ctrl::wait_on<atomic_wait::op_ne>(g_progr_ptotal, 0);
g_fxo->get<progress_dialog_workaround>().skip_the_progress_dialog = true;

// Sadly we can't postpone initializing guest time because we need ti run PPU threads
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Sadly we can't postpone initializing guest time because we need ti run PPU threads
// Sadly we can't postpone initializing guest time because we need to run PPU threads

// Save data in forward order
for (u32 i = _max; i; i--)
{
if (auto save = (*std::prev(m_info, i))->save) save(*std::prev(m_order, i), ar);
Copy link
Contributor

@Megamouse Megamouse Jun 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (auto save = (*std::prev(m_info, i))->save) save(*std::prev(m_order, i), ar);
if (auto save = (*std::prev(m_info, i))->save)
{
save(*std::prev(m_order, i), ar);
}

Copy link
Contributor

@kd-11 kd-11 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I only got halfway, there are too many instances of the same issues anyway, but the summary is pretty simple - there are way too many changes that are not directly related to savestates included here. These really should have been submitted incrementally. The reason for this is pretty simple. Users bisect on changeset, not commit. With this uber-PR, any mistakes will break the whole thing and cause emergency reverts of large sections to unbreak. It's just too difficult to follow which part potentially affects what, potential performance impact, etc. I have no doubt there will be problems - there always are will large PRs, the only difference is that this time only the original code author will be able to fix them.

@@ -694,6 +701,7 @@ namespace fs
bool trunc(u64 length) override
{
obj.resize(length);
update_time(true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unrelated to savestates. Why have it submitted with such a massive PR?

Copy link
Contributor Author

@elad335 elad335 Jul 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, this is for POSIX allowence of deletion of files with opened file descriptors in savestates. In this case I convert the file descriptor to memory and added missing functionality so it can be used by cellFs.

private:
stat_t m_stat{};

void update_time(bool write = false)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto, this should have been submitted separately, though the same can be said for large parts of this changeset.

@@ -26,11 +26,17 @@ struct loaded_npdrm_keys
}

// TODO: Check if correct for ELF files usage
u128 last_key() const
u128 last_key(usz backwards = 0) const
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also unrelated/splittable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related.

@@ -615,6 +661,11 @@ void cell_audio_thread::operator()()

thread_ctrl::scoped_priority high_prio(+1);

while (Emu.IsPaused())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An odd inclusion. Why is this here? Why now?

}

SAVESTATE_INIT_POS(2);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see a lot of these sprinkled all over the code, they really should use an enum to ease maintenance.

@@ -1975,7 +2131,17 @@ std::pair<std::shared_ptr<lv2_overlay>, CellError> ppu_load_overlay(const ppu_ex
if (prog.bin.size() > size || prog.bin.size() != prog.p_filesz)
fmt::throw_exception("Invalid binary size (0x%llx, memsz=0x%x)", prog.bin.size(), size);

if (!vm::get(vm::any, 0x30000000)->falloc(addr, size))
const bool already_loaded = ar /*&& !!(_seg.flags & 0x2)*/;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seconded. The flags check is included in other similar checks elsewhere, making this stick out.

@@ -1380,6 +1391,24 @@ void ppu_thread::cpu_task()
asm("DSB ISH");
#endif

// Wait until the progress dialog is closed.
// We don't want to open a cell dialog while a native progress dialog is still open.
thread_ctrl::wait_on<atomic_wait::op_ne>(g_progr_ptotal, 0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yet another standalone fix

{
if (g_cfg.core.ppu_decoder != ppu_decoder_type::llvm)
{
return;
}

if (auto dis = g_fxo->try_get<disable_precomp_t>(); dis && dis->disable)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this change related to savestates?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

@@ -2560,53 +2803,48 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<lv2_

std::string upper = fmt::to_upper(entry.name);

// Check .sprx filename
if (upper.ends_with(".SPRX") && entry.name != "libfs_utility_init.sprx"sv)
// Skip already loaded modules or HLEd ones
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is another improvement unrelated to the saving of states. You should have opened incremental PRs with the supporting fixes for easier risk management.

Copy link
Contributor Author

@elad335 elad335 Jul 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it's related to savestates. It's required to skip precompilation of already loaded modules with the addition of OVL modules checking which comes with savestating MGS4.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is standalone though. That's what I mean. I understand that it is needed for savestates to work, but it doesn't contain the core saving of states (serialization/deserialization) and would have been good in a part 1 PR. Again, I don't expect anything to change, but I have to give advice anyway for the sake of future PRs.

@@ -2822,20 +3060,39 @@ extern void ppu_initialize()
compile_main = ppu_initialize(_main, true);
}

std::vector<lv2_prx*> prx_list;
std::vector<ppu_module*> module_list;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here. I'm not going to check for any more standalone improvements.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, related.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Standalone, not unrelated. I'm trying to think of how to merge the whole PR without too much risk.
By standalone I mean it can be submitted separately before the "main" work, e.g in a savestates part 1 PR or something.
Not that you'll do it anyway, but still I feel it would have really helped regtesting.

@elad335
Copy link
Contributor Author

elad335 commented Jul 2, 2022

There are no unrelated changes in this pr.

@@ -2230,7 +2461,7 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
{
if (count > 20000 && g_cfg.core.perf_report) [[unlikely]]
{
perf_log.warning(u8"STCX: took too long: %.3fµs (%u c)", count / (utils::get_tsc_freq() / 1000'000.), count);
perf_log.warning(u8"STCX: took too long: %.3fµs (%u c)", count / (utils::get_tsc_freq() / 1000'000.), count);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another corrupted unicode string.

@bnthomason
Copy link

Is this a bug? In White Knight Chronicles II (Haven't tested any other game yet), doing consecutive save states (3 total, Boot Game > Save > Load Save > Save > Load Save > Save > Load Save > Crash) will cause the savestate in question to be corrupted

@Nekotekina
Copy link
Member

I think it can be merged once minor unicode string corruptions are fixed.

@vsub
Copy link

vsub commented Jul 17, 2022

Sorry for bumping this but how exactly this work?
How do I create a save state and how to load it

@AniLeo
Copy link
Member

AniLeo commented Jul 17, 2022

@vsub
Copy link

vsub commented Jul 17, 2022

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Savestates Anything that involves savestates
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Feature Request : Save state