From b17a5832e5c190859fe23b1929cefce5b7522b4a Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Wed, 27 May 2020 02:01:09 +1000 Subject: [PATCH] System: Simplify save state booting Fixes memory card warning messages on load state. --- src/core/host_interface.cpp | 36 ++----- src/core/save_state_version.h | 5 +- src/core/system.cpp | 95 +++++++++++++------ src/core/system.h | 4 +- src/frontend-common/common_host_interface.cpp | 16 +++- 5 files changed, 95 insertions(+), 61 deletions(-) diff --git a/src/core/host_interface.cpp b/src/core/host_interface.cpp index 99a6cf117..eeffacd83 100644 --- a/src/core/host_interface.cpp +++ b/src/core/host_interface.cpp @@ -82,13 +82,13 @@ void HostInterface::CreateAudioStream() bool HostInterface::BootSystem(const SystemBootParameters& parameters) { - if (parameters.filename.empty()) - Log_InfoPrintf("Boot Filename: "); - else - Log_InfoPrintf("Boot Filename: %s", parameters.filename.c_str()); - - if (!parameters.state_filename.empty()) - Log_InfoPrintf("Save State Filename: %s", parameters.filename.c_str()); + if (!parameters.state_stream) + { + if (parameters.filename.empty()) + Log_InfoPrintf("Boot Filename: "); + else + Log_InfoPrintf("Boot Filename: %s", parameters.filename.c_str()); + } if (!AcquireHostDisplay()) { @@ -111,9 +111,6 @@ bool HostInterface::BootSystem(const SystemBootParameters& parameters) return false; } - if (!parameters.state_filename.empty()) - LoadState(parameters.state_filename.c_str()); - OnSystemCreated(); m_paused = m_settings.start_paused; @@ -475,18 +472,9 @@ bool HostInterface::LoadState(const char* filename) else { SystemBootParameters boot_params; + boot_params.state_stream = std::move(stream); if (!BootSystem(boot_params)) - { - ReportFormattedError("Failed to boot system to load state from '%s'.", filename); return false; - } - - if (!m_system->LoadState(stream.get())) - { - ReportFormattedError("Failed to load state. The log may contain more information. Shutting down system."); - DestroySystem(); - return false; - } } m_system->ResetPerformanceCounters(); @@ -1219,19 +1207,13 @@ void HostInterface::RecreateSystem() DestroySystem(); SystemBootParameters boot_params; + boot_params.state_stream = std::move(stream); if (!BootSystem(boot_params)) { ReportError("Failed to boot system after recreation."); return; } - if (!m_system->LoadState(stream.get())) - { - ReportError("Failed to load state after system recreation. Shutting down."); - DestroySystem(); - return; - } - m_system->ResetPerformanceCounters(); PauseSystem(was_paused); } diff --git a/src/core/save_state_version.h b/src/core/save_state_version.h index 5a2bddb12..2d5f06b30 100644 --- a/src/core/save_state_version.h +++ b/src/core/save_state_version.h @@ -2,7 +2,7 @@ #include "types.h" static constexpr u32 SAVE_STATE_MAGIC = 0x43435544; -static constexpr u32 SAVE_STATE_VERSION = 35; +static constexpr u32 SAVE_STATE_VERSION = 36; #pragma pack(push, 4) struct SAVE_STATE_HEADER @@ -17,6 +17,9 @@ struct SAVE_STATE_HEADER u32 version; char title[MAX_TITLE_LENGTH]; char game_code[MAX_GAME_CODE_LENGTH]; + + u32 media_filename_length; + u32 offset_to_media_filename; u32 screenshot_width; u32 screenshot_height; diff --git a/src/core/system.cpp b/src/core/system.cpp index 9efa0da25..294f3df79 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -37,6 +37,13 @@ SystemBootParameters::SystemBootParameters() = default; SystemBootParameters::SystemBootParameters(std::string filename_) : filename(filename_) {} +SystemBootParameters::SystemBootParameters(const SystemBootParameters& copy) + : filename(copy.filename), override_fast_boot(copy.override_fast_boot), override_fullscreen(copy.override_fullscreen) +{ + // only exists for qt, we can't copy the state stream + Assert(!copy.state_stream); +} + SystemBootParameters::~SystemBootParameters() = default; System::System(HostInterface* host_interface) : m_host_interface(host_interface) @@ -130,6 +137,9 @@ void System::SetCPUExecutionMode(CPUExecutionMode mode) bool System::Boot(const SystemBootParameters& params) { + if (params.state_stream) + return DoLoadState(params.state_stream.get(), true); + // Load CD image up and detect region. std::unique_ptr media; bool exe_boot = false; @@ -318,34 +328,6 @@ bool System::DoState(StateWrapper& sw) sw.Do(&m_internal_frame_number); sw.Do(&m_global_tick_counter); - std::string media_filename = m_cdrom->GetMediaFileName(); - sw.Do(&media_filename); - - bool media_is_bad = false; - if (sw.IsReading()) - { - std::unique_ptr media; - if (!media_filename.empty()) - { - media = CDImage::Open(media_filename.c_str()); - if (!media) - { - Log_ErrorPrintf("Failed to open CD image from save state: '%s'. Disc will be removed.", media_filename.c_str()); - media_is_bad = true; - } - } - - UpdateRunningGame(media_filename.c_str(), media.get()); - if (GetSettings().HasAnyPerGameMemoryCards()) - UpdateMemoryCards(); - - m_cdrom->Reset(); - if (media) - m_cdrom->InsertMedia(std::move(media)); - else - m_cdrom->RemoveMedia(); - } - if (!sw.DoMarker("CPU") || !m_cpu->DoState(sw)) return false; @@ -385,9 +367,6 @@ bool System::DoState(StateWrapper& sw) if (!sw.DoMarker("Events") || !DoEventsState(sw)) return false; - if (media_is_bad) - m_cdrom->RemoveMedia(true); - return !sw.HasError(); } @@ -413,6 +392,11 @@ void System::Reset() } bool System::LoadState(ByteStream* state) +{ + return DoLoadState(state, false); +} + +bool System::DoLoadState(ByteStream* state, bool init_components) { SAVE_STATE_HEADER header; if (!state->Read2(&header, sizeof(header))) @@ -428,6 +412,49 @@ bool System::LoadState(ByteStream* state) return false; } + std::string media_filename; + std::unique_ptr media; + if (header.media_filename_length > 0) + { + media_filename.resize(header.media_filename_length); + if (!state->SeekAbsolute(header.offset_to_media_filename) || + !state->Read2(media_filename.data(), header.media_filename_length)) + { + return false; + } + + media = CDImage::Open(media_filename.c_str()); + if (!media) + { + m_host_interface->ReportFormattedError("Failed to open CD image from save state: '%s'.", media_filename.c_str()); + return false; + } + } + + UpdateRunningGame(media_filename.c_str(), media.get()); + + if (init_components) + { + InitializeComponents(); + UpdateControllers(); + UpdateMemoryCards(); + + if (media) + m_cdrom->InsertMedia(std::move(media)); + } + else + { + m_cdrom->Reset(); + if (media) + m_cdrom->InsertMedia(std::move(media)); + else + m_cdrom->RemoveMedia(); + + // ensure the correct card is loaded + if (GetSettings().HasAnyPerGameMemoryCards()) + UpdateMemoryCards(); + } + if (header.data_compression_type != 0) { m_host_interface->ReportFormattedError("Unknown save state compression type %u", header.data_compression_type); @@ -455,6 +482,12 @@ bool System::SaveState(ByteStream* state) StringUtil::Strlcpy(header.title, m_running_game_title.c_str(), sizeof(header.title)); StringUtil::Strlcpy(header.game_code, m_running_game_code.c_str(), sizeof(header.game_code)); + std::string media_filename = m_cdrom->GetMediaFileName(); + header.offset_to_media_filename = static_cast(state->GetPosition()); + header.media_filename_length = static_cast(media_filename.length()); + if (!media_filename.empty() && !state->Write2(media_filename.data(), header.media_filename_length)) + return false; + // save screenshot { const u32 screenshot_width = 128; diff --git a/src/core/system.h b/src/core/system.h index 43703196e..85a807816 100644 --- a/src/core/system.h +++ b/src/core/system.h @@ -32,12 +32,13 @@ struct SystemBootParameters { SystemBootParameters(); SystemBootParameters(std::string filename_); + SystemBootParameters(const SystemBootParameters& copy); ~SystemBootParameters(); std::string filename; - std::string state_filename; std::optional override_fast_boot; std::optional override_fullscreen; + std::unique_ptr state_stream; }; class System @@ -143,6 +144,7 @@ public: private: System(HostInterface* host_interface); + bool DoLoadState(ByteStream* stream, bool init_components); bool DoState(StateWrapper& sw); bool CreateGPU(GPURenderer renderer); diff --git a/src/frontend-common/common_host_interface.cpp b/src/frontend-common/common_host_interface.cpp index 7ac9b0e22..246128198 100644 --- a/src/frontend-common/common_host_interface.cpp +++ b/src/frontend-common/common_host_interface.cpp @@ -1,6 +1,7 @@ #include "common_host_interface.h" #include "common/assert.h" #include "common/audio_stream.h" +#include "common/byte_stream.h" #include "common/file_system.h" #include "common/log.h" #include "common/string_util.h" @@ -289,9 +290,22 @@ bool CommonHostInterface::ParseCommandLineParameters(int argc, char* argv[], std::unique_ptr boot_params = std::make_unique(); boot_params->filename = std::move(boot_filename); - boot_params->state_filename = std::move(state_filename); boot_params->override_fast_boot = std::move(force_fast_boot); boot_params->override_fullscreen = std::move(force_fullscreen); + + if (!state_filename.empty()) + { + std::unique_ptr state_stream = + FileSystem::OpenFile(state_filename.c_str(), BYTESTREAM_OPEN_READ | BYTESTREAM_OPEN_STREAMED); + if (!state_stream) + { + Log_ErrorPrintf("Failed to open save state file '%s'", state_filename.c_str()); + return false; + } + + boot_params->state_stream = std::move(state_stream); + } + *out_boot_params = std::move(boot_params); }