System: Simplify save state booting

Fixes memory card warning messages on load state.
This commit is contained in:
Connor McLaughlin 2020-05-27 02:01:09 +10:00
parent d2c7639dd8
commit b17a5832e5
5 changed files with 95 additions and 61 deletions

View File

@ -82,13 +82,13 @@ void HostInterface::CreateAudioStream()
bool HostInterface::BootSystem(const SystemBootParameters& parameters)
{
if (parameters.filename.empty())
Log_InfoPrintf("Boot Filename: <BIOS/Shell>");
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: <BIOS/Shell>");
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);
}

View File

@ -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;

View File

@ -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<CDImage> 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<CDImage> 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<CDImage> 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<u32>(state->GetPosition());
header.media_filename_length = static_cast<u32>(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;

View File

@ -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<bool> override_fast_boot;
std::optional<bool> override_fullscreen;
std::unique_ptr<ByteStream> 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);

View File

@ -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<SystemBootParameters> boot_params = std::make_unique<SystemBootParameters>();
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<ByteStream> 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);
}