core: Partially persist emulation state across game boots.

This commit is contained in:
bunnei 2022-09-10 01:48:15 -07:00
parent 1b787adbd0
commit a4d11f4427
8 changed files with 65 additions and 58 deletions

View file

@ -133,6 +133,30 @@ struct System::Impl {
: kernel{system}, fs_controller{system}, memory{system}, hid_core{}, room_network{}, : kernel{system}, fs_controller{system}, memory{system}, hid_core{}, room_network{},
cpu_manager{system}, reporter{system}, applet_manager{system}, time_manager{system} {} cpu_manager{system}, reporter{system}, applet_manager{system}, time_manager{system} {}
void Initialize(System& system) {
device_memory = std::make_unique<Core::DeviceMemory>();
is_multicore = Settings::values.use_multi_core.GetValue();
core_timing.SetMulticore(is_multicore);
core_timing.Initialize([&system]() { system.RegisterHostThread(); });
const auto posix_time = std::chrono::system_clock::now().time_since_epoch();
const auto current_time =
std::chrono::duration_cast<std::chrono::seconds>(posix_time).count();
Settings::values.custom_rtc_differential =
Settings::values.custom_rtc.value_or(current_time) - current_time;
// Create a default fs if one doesn't already exist.
if (virtual_filesystem == nullptr)
virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>();
if (content_provider == nullptr)
content_provider = std::make_unique<FileSys::ContentProviderUnion>();
// Create default implementations of applets if one is not provided.
applet_manager.SetDefaultAppletsIfMissing();
}
SystemResultStatus Run() { SystemResultStatus Run() {
std::unique_lock<std::mutex> lk(suspend_guard); std::unique_lock<std::mutex> lk(suspend_guard);
status = SystemResultStatus::Success; status = SystemResultStatus::Success;
@ -178,37 +202,17 @@ struct System::Impl {
debugger = std::make_unique<Debugger>(system, port); debugger = std::make_unique<Debugger>(system, port);
} }
SystemResultStatus Init(System& system, Frontend::EmuWindow& emu_window) { SystemResultStatus SetupForMainProcess(System& system, Frontend::EmuWindow& emu_window) {
LOG_DEBUG(Core, "initialized OK"); LOG_DEBUG(Core, "initialized OK");
device_memory = std::make_unique<Core::DeviceMemory>();
is_multicore = Settings::values.use_multi_core.GetValue();
is_async_gpu = Settings::values.use_asynchronous_gpu_emulation.GetValue(); is_async_gpu = Settings::values.use_asynchronous_gpu_emulation.GetValue();
kernel.SetMulticore(is_multicore); kernel.SetMulticore(is_multicore);
cpu_manager.SetMulticore(is_multicore); cpu_manager.SetMulticore(is_multicore);
cpu_manager.SetAsyncGpu(is_async_gpu); cpu_manager.SetAsyncGpu(is_async_gpu);
core_timing.SetMulticore(is_multicore);
kernel.Initialize(); kernel.Initialize();
cpu_manager.Initialize(); cpu_manager.Initialize();
core_timing.Initialize([&system]() { system.RegisterHostThread(); });
const auto posix_time = std::chrono::system_clock::now().time_since_epoch();
const auto current_time =
std::chrono::duration_cast<std::chrono::seconds>(posix_time).count();
Settings::values.custom_rtc_differential =
Settings::values.custom_rtc.value_or(current_time) - current_time;
// Create a default fs if one doesn't already exist.
if (virtual_filesystem == nullptr)
virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>();
if (content_provider == nullptr)
content_provider = std::make_unique<FileSys::ContentProviderUnion>();
/// Create default implementations of applets if one is not provided.
applet_manager.SetDefaultAppletsIfMissing();
/// Reset all glue registrations /// Reset all glue registrations
arp_manager.ResetAll(); arp_manager.ResetAll();
@ -253,11 +257,11 @@ struct System::Impl {
return SystemResultStatus::ErrorGetLoader; return SystemResultStatus::ErrorGetLoader;
} }
SystemResultStatus init_result{Init(system, emu_window)}; SystemResultStatus init_result{SetupForMainProcess(system, emu_window)};
if (init_result != SystemResultStatus::Success) { if (init_result != SystemResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to initialize system (Error {})!", LOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
static_cast<int>(init_result)); static_cast<int>(init_result));
Shutdown(); ShutdownMainProcess();
return init_result; return init_result;
} }
@ -276,7 +280,7 @@ struct System::Impl {
const auto [load_result, load_parameters] = app_loader->Load(*main_process, system); const auto [load_result, load_parameters] = app_loader->Load(*main_process, system);
if (load_result != Loader::ResultStatus::Success) { if (load_result != Loader::ResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", load_result); LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", load_result);
Shutdown(); ShutdownMainProcess();
return static_cast<SystemResultStatus>( return static_cast<SystemResultStatus>(
static_cast<u32>(SystemResultStatus::ErrorLoader) + static_cast<u32>(load_result)); static_cast<u32>(SystemResultStatus::ErrorLoader) + static_cast<u32>(load_result));
@ -335,7 +339,7 @@ struct System::Impl {
return status; return status;
} }
void Shutdown() { void ShutdownMainProcess() {
SetShuttingDown(true); SetShuttingDown(true);
// Log last frame performance stats if game was loded // Log last frame performance stats if game was loded
@ -369,7 +373,7 @@ struct System::Impl {
cheat_engine.reset(); cheat_engine.reset();
telemetry_session.reset(); telemetry_session.reset();
time_manager.Shutdown(); time_manager.Shutdown();
core_timing.Shutdown(); core_timing.ClearPendingEvents();
app_loader.reset(); app_loader.reset();
audio_core.reset(); audio_core.reset();
gpu_core.reset(); gpu_core.reset();
@ -377,7 +381,6 @@ struct System::Impl {
perf_stats.reset(); perf_stats.reset();
kernel.Shutdown(); kernel.Shutdown();
memory.Reset(); memory.Reset();
applet_manager.ClearAll();
if (auto room_member = room_network.GetRoomMember().lock()) { if (auto room_member = room_network.GetRoomMember().lock()) {
Network::GameInfo game_info{}; Network::GameInfo game_info{};
@ -520,6 +523,10 @@ const CpuManager& System::GetCpuManager() const {
return impl->cpu_manager; return impl->cpu_manager;
} }
void System::Initialize() {
impl->Initialize(*this);
}
SystemResultStatus System::Run() { SystemResultStatus System::Run() {
return impl->Run(); return impl->Run();
} }
@ -540,8 +547,8 @@ void System::InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size) {
impl->kernel.InvalidateCpuInstructionCacheRange(addr, size); impl->kernel.InvalidateCpuInstructionCacheRange(addr, size);
} }
void System::Shutdown() { void System::ShutdownMainProcess() {
impl->Shutdown(); impl->ShutdownMainProcess();
} }
bool System::IsShuttingDown() const { bool System::IsShuttingDown() const {

View file

@ -142,6 +142,12 @@ public:
System(System&&) = delete; System(System&&) = delete;
System& operator=(System&&) = delete; System& operator=(System&&) = delete;
/**
* Initializes the system
* This function will initialize core functionaility used for system emulation
*/
void Initialize();
/** /**
* Run the OS and Application * Run the OS and Application
* This function will start emulation and run the relevant devices * This function will start emulation and run the relevant devices
@ -166,8 +172,8 @@ public:
void InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size); void InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size);
/// Shutdown the emulated system. /// Shutdown the main emulated process.
void Shutdown(); void ShutdownMainProcess();
/// Check if the core is shutting down. /// Check if the core is shutting down.
[[nodiscard]] bool IsShuttingDown() const; [[nodiscard]] bool IsShuttingDown() const;

View file

@ -40,7 +40,17 @@ struct CoreTiming::Event {
CoreTiming::CoreTiming() CoreTiming::CoreTiming()
: clock{Common::CreateBestMatchingClock(Hardware::BASE_CLOCK_RATE, Hardware::CNTFREQ)} {} : clock{Common::CreateBestMatchingClock(Hardware::BASE_CLOCK_RATE, Hardware::CNTFREQ)} {}
CoreTiming::~CoreTiming() = default; CoreTiming::~CoreTiming() {
paused = true;
shutting_down = true;
pause_event.Set();
event.Set();
if (timer_thread) {
timer_thread->join();
}
timer_thread.reset();
has_started = false;
}
void CoreTiming::ThreadEntry(CoreTiming& instance) { void CoreTiming::ThreadEntry(CoreTiming& instance) {
constexpr char name[] = "HostTiming"; constexpr char name[] = "HostTiming";
@ -65,17 +75,8 @@ void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) {
} }
} }
void CoreTiming::Shutdown() { void CoreTiming::ClearPendingEvents() {
paused = true; event_queue.clear();
shutting_down = true;
pause_event.Set();
event.Set();
if (timer_thread) {
timer_thread->join();
}
ClearPendingEvents();
timer_thread.reset();
has_started = false;
} }
void CoreTiming::Pause(bool is_paused) { void CoreTiming::Pause(bool is_paused) {
@ -196,10 +197,6 @@ u64 CoreTiming::GetClockTicks() const {
return CpuCyclesToClockCycles(ticks); return CpuCyclesToClockCycles(ticks);
} }
void CoreTiming::ClearPendingEvents() {
event_queue.clear();
}
void CoreTiming::RemoveEvent(const std::shared_ptr<EventType>& event_type) { void CoreTiming::RemoveEvent(const std::shared_ptr<EventType>& event_type) {
std::scoped_lock lock{basic_lock}; std::scoped_lock lock{basic_lock};

View file

@ -61,8 +61,8 @@ public:
/// required to end slice - 1 and start slice 0 before the first cycle of code is executed. /// required to end slice - 1 and start slice 0 before the first cycle of code is executed.
void Initialize(std::function<void()>&& on_thread_init_); void Initialize(std::function<void()>&& on_thread_init_);
/// Tears down all timing related functionality. /// Clear all pending events. This should ONLY be done on exit.
void Shutdown(); void ClearPendingEvents();
/// Sets if emulation is multicore or single core, must be set before Initialize /// Sets if emulation is multicore or single core, must be set before Initialize
void SetMulticore(bool is_multicore_) { void SetMulticore(bool is_multicore_) {
@ -136,9 +136,6 @@ public:
private: private:
struct Event; struct Event;
/// Clear all pending events. This should ONLY be done on exit.
void ClearPendingEvents();
static void ThreadEntry(CoreTiming& instance); static void ThreadEntry(CoreTiming& instance);
void ThreadLoop(); void ThreadLoop();

View file

@ -40,9 +40,6 @@ struct ScopeInit final {
core_timing.SetMulticore(true); core_timing.SetMulticore(true);
core_timing.Initialize([]() {}); core_timing.Initialize([]() {});
} }
~ScopeInit() {
core_timing.Shutdown();
}
Core::Timing::CoreTiming core_timing; Core::Timing::CoreTiming core_timing;
}; };

View file

@ -120,8 +120,8 @@ void EmuThread::run() {
} }
} }
// Shutdown the core emulation // Shutdown the main emulated process
system.Shutdown(); system.ShutdownMainProcess();
#if MICROPROFILE_ENABLED #if MICROPROFILE_ENABLED
MicroProfileOnThreadExit(); MicroProfileOnThreadExit();

View file

@ -294,6 +294,7 @@ GMainWindow::GMainWindow(std::unique_ptr<Config> config_, bool has_broken_vulkan
#ifdef __linux__ #ifdef __linux__
SetupSigInterrupts(); SetupSigInterrupts();
#endif #endif
system->Initialize();
Common::Log::Initialize(); Common::Log::Initialize();
LoadTranslation(); LoadTranslation();

View file

@ -302,6 +302,8 @@ int main(int argc, char** argv) {
} }
Core::System system{}; Core::System system{};
system.Initialize();
InputCommon::InputSubsystem input_subsystem{}; InputCommon::InputSubsystem input_subsystem{};
// Apply the command line arguments // Apply the command line arguments
@ -392,7 +394,7 @@ int main(int argc, char** argv) {
} }
system.DetachDebugger(); system.DetachDebugger();
void(system.Pause()); void(system.Pause());
system.Shutdown(); system.ShutdownMainProcess();
detached_tasks.WaitForAllTasks(); detached_tasks.WaitForAllTasks();
return 0; return 0;