From 962230f91e06a60b2395de6f0974fdd213854d4c Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 2 Jun 2024 15:10:25 +0200 Subject: [PATCH 1/2] Core: Store current state in less places Core::GetState reads from four different pieces of state: s_is_stopping, s_hardware_initialized, s_is_booting, and CPUManager::IsStepping. I'm keeping that last one as is for now because there's code in Dolphin that sets it directly, but we can unify the other three to make things easier to reason about. This commit also gets rid of s_is_started. This was previously used in Core::IsRunningAndStarted to ensure true wouldn't be returned until the CPU thread was started, but it wasn't used in Core::GetState, so Core::GetState would happily return State::Running after we had initialized the hardware but before we had initialized the CPU thread. As far as I know, there are no callers that have any real need to know whether the boot process is currently initializing the hardware or the CPU thread. Perhaps once upon a time there was a desire to make the apploader debuggable, but a long time has passed without anyone stepping up to implement it, and the way CBoot::RunApploader is implemented makes it rather difficult. So this commit makes all the functions in Core.cpp consider the core to still be starting until the CPU thread is started. --- Source/Android/jni/MainAndroid.cpp | 2 +- Source/Core/Core/ConfigManager.cpp | 10 +-- Source/Core/Core/Core.cpp | 90 ++++++++----------- Source/Core/Core/Core.h | 4 +- .../Core/Core/Debugger/PPCDebugInterface.cpp | 2 +- Source/Core/Core/IOS/ES/ES.cpp | 8 +- Source/Core/Core/IOS/IOS.cpp | 2 +- Source/Core/Core/Movie.cpp | 6 +- Source/Core/Core/State.cpp | 2 +- Source/Core/DolphinQt/HotkeyScheduler.cpp | 5 +- Source/Core/DolphinQt/MainWindow.cpp | 2 +- Source/Core/DolphinQt/RenderWidget.cpp | 2 +- Source/Core/VideoCommon/VideoConfig.cpp | 2 +- 13 files changed, 61 insertions(+), 76 deletions(-) diff --git a/Source/Android/jni/MainAndroid.cpp b/Source/Android/jni/MainAndroid.cpp index 9fcf1b33a3..66a0694a94 100644 --- a/Source/Android/jni/MainAndroid.cpp +++ b/Source/Android/jni/MainAndroid.cpp @@ -279,7 +279,7 @@ JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_IsRunnin JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_IsRunningAndStarted(JNIEnv*, jclass) { - return static_cast(Core::IsRunningAndStarted()); + return static_cast(Core::IsRunning(Core::System::GetInstance())); } JNIEXPORT jboolean JNICALL diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp index e3c1ec1d15..8882076daa 100644 --- a/Source/Core/Core/ConfigManager.cpp +++ b/Source/Core/Core/ConfigManager.cpp @@ -185,22 +185,22 @@ void SConfig::SetRunningGameMetadata(const std::string& game_id, const std::stri m_title_description = title_database.Describe(m_gametdb_id, language); NOTICE_LOG_FMT(CORE, "Active title: {}", m_title_description); Host_TitleChanged(); - if (Core::IsRunning(system)) - { + + const bool is_running_or_starting = Core::IsRunningOrStarting(system); + if (is_running_or_starting) Core::UpdateTitle(system); - } Config::AddLayer(ConfigLoaders::GenerateGlobalGameConfigLoader(game_id, revision)); Config::AddLayer(ConfigLoaders::GenerateLocalGameConfigLoader(game_id, revision)); - if (Core::IsRunning(system)) + if (is_running_or_starting) DolphinAnalytics::Instance().ReportGameStart(); } void SConfig::OnNewTitleLoad(const Core::CPUThreadGuard& guard) { auto& system = guard.GetSystem(); - if (!Core::IsRunning(system)) + if (!Core::IsRunningOrStarting(system)) return; auto& ppc_symbol_db = system.GetPPCSymbolDB(); diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index f28a41f836..58423377be 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -101,10 +101,6 @@ namespace Core static bool s_wants_determinism; // Declarations and definitions -static bool s_is_stopping = false; -static bool s_hardware_initialized = false; -static bool s_is_started = false; -static Common::Flag s_is_booting; static std::thread s_emu_thread; static std::vector s_on_state_changed_callbacks; @@ -114,6 +110,10 @@ static std::atomic s_last_actual_emulation_speed{1.0}; static bool s_frame_step = false; static std::atomic s_stop_frame_step; +// The value Paused is never stored in this variable. The core is considered to be in +// the Paused state if this variable is Running and the CPU reports that it's stepping. +static std::atomic s_state = State::Uninitialized; + #ifdef USE_MEMORYWATCHER static std::unique_ptr s_memory_watcher; #endif @@ -190,7 +190,7 @@ std::string StopMessage(bool main_thread, std::string_view message) void DisplayMessage(std::string message, int time_in_ms) { - if (!IsRunning(Core::System::GetInstance())) + if (!IsRunningOrStarting(Core::System::GetInstance())) return; // Actually displaying non-ASCII could cause things to go pear-shaped @@ -202,12 +202,13 @@ void DisplayMessage(std::string message, int time_in_ms) bool IsRunning(Core::System& system) { - return (GetState(system) != State::Uninitialized || s_hardware_initialized) && !s_is_stopping; + return s_state.load() == State::Running; } -bool IsRunningAndStarted() +bool IsRunningOrStarting(Core::System& system) { - return s_is_started && !s_is_stopping; + const State state = s_state.load(); + return state == State::Running || state == State::Starting; } bool IsCPUThread() @@ -262,7 +263,7 @@ bool Init(Core::System& system, std::unique_ptr boot, const Wind g_video_backend->PrepareWindow(prepared_wsi); // Start the emu thread - s_is_booting.Set(); + s_state.store(State::Starting); s_emu_thread = std::thread(EmuThread, std::ref(system), std::move(boot), prepared_wsi); return true; } @@ -281,15 +282,13 @@ static void ResetRumble() // Called from GUI thread void Stop(Core::System& system) // - Hammertime! { - if (const State state = GetState(system); - state == State::Stopping || state == State::Uninitialized) - { + const State state = s_state.load(); + if (state == State::Stopping || state == State::Uninitialized) return; - } AchievementManager::GetInstance().CloseGame(); - s_is_stopping = true; + s_state.store(State::Stopping); CallOnStateChangedCallbacks(State::Stopping); @@ -394,7 +393,11 @@ static void CpuThread(Core::System& system, const std::optional& sa File::Delete(*savestate_path); } - s_is_started = true; + // If s_state is Starting, change it to Running. But if it's already been set to Stopping + // by the host thread, don't change it. + State expected = State::Starting; + s_state.compare_exchange_strong(expected, State::Running); + { #ifndef _WIN32 std::string gdb_socket = Config::Get(Config::MAIN_GDB_SOCKET); @@ -426,8 +429,6 @@ static void CpuThread(Core::System& system, const std::optional& sa s_memory_watcher.reset(); #endif - s_is_started = false; - if (exception_handler) EMM::UninstallExceptionHandler(); @@ -453,12 +454,15 @@ static void FifoPlayerThread(Core::System& system, const std::optional boot { CallOnStateChangedCallbacks(State::Starting); Common::ScopeGuard flag_guard{[] { - s_is_booting.Clear(); - s_is_started = false; - s_is_stopping = false; - s_wants_determinism = false; + s_state.store(State::Uninitialized); CallOnStateChangedCallbacks(State::Uninitialized); @@ -557,8 +558,6 @@ static void EmuThread(Core::System& system, std::unique_ptr boot NetPlay::IsNetPlayRunning() ? &(boot_session_data.GetNetplaySettings()->sram) : nullptr); Common::ScopeGuard hw_guard{[&system] { - // We must set up this flag before executing HW::Shutdown() - s_hardware_initialized = false; INFO_LOG_FMT(CONSOLE, "{}", StopMessage(false, "Shutting down HW")); HW::Shutdown(system); INFO_LOG_FMT(CONSOLE, "{}", StopMessage(false, "HW shutdown")); @@ -602,10 +601,6 @@ static void EmuThread(Core::System& system, std::unique_ptr boot AudioCommon::PostInitSoundStream(system); - // The hardware is initialized. - s_hardware_initialized = true; - s_is_booting.Clear(); - // Set execution state to known values (CPU/FIFO/Audio Paused) system.GetCPU().Break(); @@ -701,7 +696,7 @@ static void EmuThread(Core::System& system, std::unique_ptr boot void SetState(Core::System& system, State state, bool report_state_change) { // State cannot be controlled until the CPU Thread is operational - if (!IsRunningAndStarted()) + if (s_state.load() != State::Running) return; switch (state) @@ -732,21 +727,11 @@ void SetState(Core::System& system, State state, bool report_state_change) State GetState(Core::System& system) { - if (s_is_stopping) - return State::Stopping; - - if (s_hardware_initialized) - { - if (system.GetCPU().IsStepping()) - return State::Paused; - - return State::Running; - } - - if (s_is_booting.IsSet()) - return State::Starting; - - return State::Uninitialized; + const State state = s_state.load(); + if (state == State::Running && system.GetCPU().IsStepping()) + return State::Paused; + else + return state; } static std::string GenerateScreenshotFolderPath() @@ -800,7 +785,7 @@ static bool PauseAndLock(Core::System& system, bool do_lock, bool unpause_on_unl { // WARNING: PauseAndLock is not fully threadsafe so is only valid on the Host Thread - if (!IsRunningAndStarted()) + if (!IsRunning(system)) return true; bool was_unpaused = true; @@ -1027,13 +1012,12 @@ void HostDispatchJobs(Core::System& system) HostJob job = std::move(s_host_jobs_queue.front()); s_host_jobs_queue.pop(); - // NOTE: Memory ordering is important. The booting flag needs to be - // checked first because the state transition is: - // Core::State::Uninitialized: s_is_booting -> s_hardware_initialized - // We need to check variables in the same order as the state - // transition, otherwise we race and get transient failures. - if (!job.run_after_stop && !s_is_booting.IsSet() && !IsRunning(system)) - continue; + if (!job.run_after_stop) + { + const State state = s_state.load(); + if (state == State::Stopping || state == State::Uninitialized) + continue; + } guard.unlock(); job.job(system); diff --git a/Source/Core/Core/Core.h b/Source/Core/Core/Core.h index 980d336750..e6c440566c 100644 --- a/Source/Core/Core/Core.h +++ b/Source/Core/Core/Core.h @@ -135,8 +135,8 @@ void UndeclareAsHostThread(); std::string StopMessage(bool main_thread, std::string_view message); bool IsRunning(Core::System& system); -bool IsRunningAndStarted(); // is running and the CPU loop has been entered -bool IsCPUThread(); // this tells us whether we are the CPU thread. +bool IsRunningOrStarting(Core::System& system); +bool IsCPUThread(); // this tells us whether we are the CPU thread. bool IsGPUThread(); bool IsHostThread(); diff --git a/Source/Core/Core/Debugger/PPCDebugInterface.cpp b/Source/Core/Core/Debugger/PPCDebugInterface.cpp index a003e98156..9389fe76d8 100644 --- a/Source/Core/Core/Debugger/PPCDebugInterface.cpp +++ b/Source/Core/Core/Debugger/PPCDebugInterface.cpp @@ -349,7 +349,7 @@ u32 PPCDebugInterface::ReadInstruction(const Core::CPUThreadGuard& guard, u32 ad bool PPCDebugInterface::IsAlive() const { - return Core::IsRunningAndStarted(); + return Core::IsRunning(m_system); } bool PPCDebugInterface::IsBreakpoint(u32 address) const diff --git a/Source/Core/Core/IOS/ES/ES.cpp b/Source/Core/Core/IOS/ES/ES.cpp index 6bd894dd27..d04a3ef889 100644 --- a/Source/Core/Core/IOS/ES/ES.cpp +++ b/Source/Core/Core/IOS/ES/ES.cpp @@ -112,9 +112,9 @@ ESCore::~ESCore() = default; ESDevice::ESDevice(EmulationKernel& ios, ESCore& core, const std::string& device_name) : EmulationDevice(ios, device_name), m_core(core) { - if (Core::IsRunningAndStarted()) + auto& system = ios.GetSystem(); + if (Core::IsRunning(system)) { - auto& system = ios.GetSystem(); auto& core_timing = system.GetCoreTiming(); core_timing.RemoveEvent(s_finish_init_event); core_timing.ScheduleEvent(GetESBootTicks(ios.GetVersion()), s_finish_init_event); @@ -446,7 +446,7 @@ bool ESDevice::LaunchPPCTitle(u64 title_id) } const u64 required_ios = tmd.GetIOSId(); - if (!Core::IsRunningAndStarted()) + if (!Core::IsRunning(system)) return LaunchTitle(required_ios, HangPPC::Yes); core_timing.RemoveEvent(s_reload_ios_for_ppc_launch_event); core_timing.ScheduleEvent(ticks, s_reload_ios_for_ppc_launch_event, required_ios); @@ -475,7 +475,7 @@ bool ESDevice::LaunchPPCTitle(u64 title_id) return false; m_pending_ppc_boot_content_path = m_core.GetContentPath(tmd.GetTitleId(), content); - if (!Core::IsRunningAndStarted()) + if (!Core::IsRunning(system)) return BootstrapPPC(); INFO_LOG_FMT(ACHIEVEMENTS, diff --git a/Source/Core/Core/IOS/IOS.cpp b/Source/Core/Core/IOS/IOS.cpp index 0e046b8534..d15eb9317d 100644 --- a/Source/Core/Core/IOS/IOS.cpp +++ b/Source/Core/Core/IOS/IOS.cpp @@ -518,7 +518,7 @@ bool EmulationKernel::BootIOS(const u64 ios_title_id, HangPPC hang_ppc, if (hang_ppc == HangPPC::Yes) ResetAndPausePPC(m_system); - if (Core::IsRunningAndStarted()) + if (Core::IsRunning(m_system)) { m_system.GetCoreTiming().ScheduleEvent(GetIOSBootTicks(GetVersion()), s_event_finish_ios_boot, ios_title_id); diff --git a/Source/Core/Core/Movie.cpp b/Source/Core/Core/Movie.cpp index 47ad3c8c97..325381f0e9 100644 --- a/Source/Core/Core/Movie.cpp +++ b/Source/Core/Core/Movie.cpp @@ -536,7 +536,7 @@ bool MovieManager::BeginRecordingInput(const ControllerTypeArray& controllers, m_bongos |= (1 << i); } - if (Core::IsRunningAndStarted()) + if (Core::IsRunning(m_system)) { const std::string save_path = File::GetUserPath(D_STATESAVES_IDX) + "dtm.sav"; if (File::Exists(save_path)) @@ -551,7 +551,7 @@ bool MovieManager::BeginRecordingInput(const ControllerTypeArray& controllers, } // Wiimotes cause desync issues if they're not reset before launching the game - if (!Core::IsRunningAndStarted()) + if (!Core::IsRunning(m_system)) { // This will also reset the Wiimotes for GameCube games, but that shouldn't do anything Wiimote::ResetAllWiimotes(); @@ -1339,7 +1339,7 @@ void MovieManager::EndPlayInput(bool cont) { // We can be called by EmuThread during boot (CPU::State::PowerDown) auto& cpu = m_system.GetCPU(); - const bool was_running = Core::IsRunningAndStarted() && !cpu.IsStepping(); + const bool was_running = Core::IsRunning(m_system) && !cpu.IsStepping(); if (was_running && Config::Get(Config::MAIN_MOVIE_PAUSE_MOVIE)) cpu.Break(); m_rerecords = 0; diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp index adc1cbd57a..11c8e9660e 100644 --- a/Source/Core/Core/State.cpp +++ b/Source/Core/Core/State.cpp @@ -854,7 +854,7 @@ static void LoadFileStateData(const std::string& filename, std::vector& ret_ void LoadAs(Core::System& system, const std::string& filename) { - if (!Core::IsRunning(system)) + if (!Core::IsRunningOrStarting(system)) return; if (NetPlay::IsNetPlayRunning()) diff --git a/Source/Core/DolphinQt/HotkeyScheduler.cpp b/Source/Core/DolphinQt/HotkeyScheduler.cpp index 10f7540ca7..0a6d13e6c0 100644 --- a/Source/Core/DolphinQt/HotkeyScheduler.cpp +++ b/Source/Core/DolphinQt/HotkeyScheduler.cpp @@ -159,7 +159,8 @@ void HotkeyScheduler::Run() if (!HotkeyManagerEmu::IsEnabled()) continue; - if (Core::GetState(Core::System::GetInstance()) != Core::State::Stopping) + Core::System& system = Core::System::GetInstance(); + if (Core::GetState(system) != Core::State::Stopping) { // Obey window focus (config permitting) before checking hotkeys. Core::UpdateInputGate(Config::Get(Config::MAIN_FOCUSED_HOTKEYS)); @@ -187,7 +188,7 @@ void HotkeyScheduler::Run() if (IsHotkey(HK_EXIT)) emit ExitHotkey(); - if (!Core::IsRunningAndStarted()) + if (!Core::IsRunning(system)) { // Only check for Play Recording hotkey when no game is running if (IsHotkey(HK_PLAY_RECORDING)) diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index 67860c464a..f62a7496e7 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -1882,7 +1882,7 @@ void MainWindow::OnStartRecording() { auto& system = Core::System::GetInstance(); auto& movie = system.GetMovie(); - if ((!Core::IsRunningAndStarted() && Core::IsRunning(system)) || movie.IsRecordingInput() || + if (Core::GetState(system) == Core::State::Starting || movie.IsRecordingInput() || movie.IsPlayingInput()) { return; diff --git a/Source/Core/DolphinQt/RenderWidget.cpp b/Source/Core/DolphinQt/RenderWidget.cpp index 597ac78e6c..d88a17e3d3 100644 --- a/Source/Core/DolphinQt/RenderWidget.cpp +++ b/Source/Core/DolphinQt/RenderWidget.cpp @@ -513,7 +513,7 @@ bool RenderWidget::event(QEvent* event) void RenderWidget::PassEventToPresenter(const QEvent* event) { - if (!Core::IsRunningAndStarted()) + if (!Core::IsRunning(Core::System::GetInstance())) return; switch (event->type()) diff --git a/Source/Core/VideoCommon/VideoConfig.cpp b/Source/Core/VideoCommon/VideoConfig.cpp index 0266cb9c19..efa159795c 100644 --- a/Source/Core/VideoCommon/VideoConfig.cpp +++ b/Source/Core/VideoCommon/VideoConfig.cpp @@ -66,7 +66,7 @@ void VideoConfig::Refresh() CPUThreadConfigCallback::AddConfigChangedCallback([]() { auto& system = Core::System::GetInstance(); - const bool lock_gpu_thread = Core::IsRunningAndStarted(); + const bool lock_gpu_thread = Core::IsRunning(system); if (lock_gpu_thread) system.GetFifo().PauseAndLock(true, false); From 72cf2bdb87f09deff22e1085de3290126aa4ad05 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 2 Jun 2024 16:45:30 +0200 Subject: [PATCH 2/2] Audit uses of IsRunning and GetState Some pieces of code are calling IsRunning because there's some particular action that only makes sense when emulation is running, for instance showing the state of the emulated CPU. IsRunning is appropriate to use for this. Then there are pieces of code that are calling IsRunning because there's some particular thing they must avoid doing e.g. when the CPU thread is running or IOS is running. IsRunning isn't quite appropriate for this. Such code should also be checking for the states Starting and Stopping. Keep in mind that: * When the state is Starting, the state can asynchronously change to Running at any time. * When we try to stop the core, the state gets set to Stopping before we take any action to actually stop things. This commit adds a new method Core::IsUninitialized, and changes all callers of IsRunning and GetState that look to me like they should be changed. --- .../dolphinemu/dolphinemu/NativeLibrary.java | 10 +++- .../features/settings/model/Settings.kt | 2 +- .../settings/model/view/RunRunnable.kt | 2 +- .../settings/model/view/SettingsItem.kt | 2 +- .../settings/ui/SettingsFragmentPresenter.kt | 4 +- .../dolphinemu/fragments/EmulationFragment.kt | 8 +-- .../dolphinemu/overlay/InputOverlay.kt | 2 +- Source/Android/jni/MainAndroid.cpp | 17 +++--- .../Core/ConfigLoaders/BaseConfigLoader.cpp | 4 +- Source/Core/Core/Core.cpp | 7 ++- Source/Core/Core/Core.h | 5 ++ .../AchievementSettingsWidget.cpp | 11 ++-- .../DolphinQt/CheatSearchFactoryWidget.cpp | 3 +- Source/Core/DolphinQt/CheatsManager.cpp | 5 +- .../DolphinQt/Config/CheatWarningWidget.cpp | 5 +- .../Config/Graphics/AdvancedWidget.cpp | 3 +- .../Config/Graphics/GeneralWidget.cpp | 6 +-- .../DolphinQt/Debugger/AssemblerWidget.cpp | 2 +- .../DolphinQt/Debugger/BreakpointWidget.cpp | 2 +- .../DolphinQt/Debugger/CodeViewWidget.cpp | 2 +- .../Core/DolphinQt/Debugger/ThreadWidget.cpp | 2 +- .../Core/DolphinQt/Debugger/WatchWidget.cpp | 5 +- .../Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp | 27 ++++++---- Source/Core/DolphinQt/GameList/GameList.cpp | 12 ++--- Source/Core/DolphinQt/HotkeyScheduler.cpp | 2 +- Source/Core/DolphinQt/MainWindow.cpp | 15 +++--- Source/Core/DolphinQt/MenuBar.cpp | 54 +++++++++++-------- Source/Core/DolphinQt/MenuBar.h | 2 +- .../Core/DolphinQt/NetPlay/NetPlayDialog.cpp | 2 + .../Core/DolphinQt/Settings/AdvancedPane.cpp | 2 +- Source/Core/DolphinQt/Settings/AudioPane.cpp | 3 +- Source/Core/DolphinQt/Settings/WiiPane.cpp | 3 +- Source/Core/VideoCommon/VideoConfig.cpp | 7 +-- 33 files changed, 133 insertions(+), 105 deletions(-) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java index 43880bd0ba..1cdd9fa473 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java @@ -381,10 +381,16 @@ public final class NativeLibrary */ public static native boolean IsRunning(); - public static native boolean IsRunningAndStarted(); - + /** + * Returns true if emulation is running and not paused. + */ public static native boolean IsRunningAndUnpaused(); + /** + * Returns true if emulation is fully shut down. + */ + public static native boolean IsUninitialized(); + /** * Writes out the JitBlock Cache log dump */ diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/Settings.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/Settings.kt index c5c1851e5d..eedc1405ff 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/Settings.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/Settings.kt @@ -36,7 +36,7 @@ class Settings : Closeable { if (isGameSpecific) { // Loading game INIs while the core is running will mess with the game INIs loaded by the core - check(!NativeLibrary.IsRunning()) { "Attempted to load game INI while emulating" } + check(NativeLibrary.IsUninitialized()) { "Attempted to load game INI while emulating" } NativeConfig.loadGameInis(gameId, revision) } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/RunRunnable.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/RunRunnable.kt index f9d5786e22..c52964ff0b 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/RunRunnable.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/RunRunnable.kt @@ -20,5 +20,5 @@ class RunRunnable( override val setting: AbstractSetting? = null override val isEditable: Boolean - get() = worksDuringEmulation || !NativeLibrary.IsRunning() + get() = worksDuringEmulation || NativeLibrary.IsUninitialized() } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/SettingsItem.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/SettingsItem.kt index 3209400ff6..01c4796e68 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/SettingsItem.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/SettingsItem.kt @@ -54,7 +54,7 @@ abstract class SettingsItem { open val isEditable: Boolean get() { - if (!NativeLibrary.IsRunning()) return true + if (NativeLibrary.IsUninitialized()) return true val setting = setting return setting != null && setting.isRuntimeEditable } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.kt index 6de39ed1e9..1573b6408c 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.kt @@ -69,7 +69,7 @@ class SettingsFragmentPresenter( } else if ( menuTag == MenuTag.GRAPHICS && this.gameId.isNullOrEmpty() - && !NativeLibrary.IsRunning() + && NativeLibrary.IsUninitialized() && GpuDriverHelper.supportsCustomDriverLoading() ) { this.gpuDriver = @@ -1303,7 +1303,7 @@ class SettingsFragmentPresenter( if ( this.gpuDriver != null && this.gameId.isNullOrEmpty() - && !NativeLibrary.IsRunning() + && NativeLibrary.IsUninitialized() && GpuDriverHelper.supportsCustomDriverLoading() ) { sl.add( diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.kt index 637f4fb924..eeb223c3db 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.kt @@ -180,11 +180,11 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { private fun run(isActivityRecreated: Boolean) { if (isActivityRecreated) { - if (NativeLibrary.IsRunning()) { + if (NativeLibrary.IsUninitialized()) { + loadPreviousTemporaryState = true + } else { loadPreviousTemporaryState = false deleteFile(temporaryStateFilePath) - } else { - loadPreviousTemporaryState = true } } else { Log.debug("[EmulationFragment] activity resumed or fresh start") @@ -203,7 +203,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { private fun runWithValidSurface() { runWhenSurfaceIsValid = false - if (!NativeLibrary.IsRunning()) { + if (NativeLibrary.IsUninitialized()) { NativeLibrary.SetIsBooting() val emulationThread = Thread({ if (loadPreviousTemporaryState) { diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlay.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlay.kt index dfe557e712..7964cc1ebc 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlay.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlay.kt @@ -83,7 +83,7 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex fun initTouchPointer() { // Check if we have all the data we need yet - val aspectRatioAvailable = NativeLibrary.IsRunningAndStarted() + val aspectRatioAvailable = NativeLibrary.IsRunning() if (!aspectRatioAvailable || surfacePosition == null) return diff --git a/Source/Android/jni/MainAndroid.cpp b/Source/Android/jni/MainAndroid.cpp index 66a0694a94..8febc6f633 100644 --- a/Source/Android/jni/MainAndroid.cpp +++ b/Source/Android/jni/MainAndroid.cpp @@ -118,8 +118,7 @@ void Host_Message(HostMessageID id) } else if (id == HostMessageID::WMUserStop) { - if (Core::IsRunning(Core::System::GetInstance())) - Core::QueueHostJob(&Core::Stop); + Core::QueueHostJob(&Core::Stop); } } @@ -271,13 +270,6 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetIsBooting } JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_IsRunning(JNIEnv*, jclass) -{ - return s_is_booting.IsSet() || - static_cast(Core::IsRunning(Core::System::GetInstance())); -} - -JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_IsRunningAndStarted(JNIEnv*, - jclass) { return static_cast(Core::IsRunning(Core::System::GetInstance())); } @@ -288,6 +280,13 @@ Java_org_dolphinemu_dolphinemu_NativeLibrary_IsRunningAndUnpaused(JNIEnv*, jclas return static_cast(Core::GetState(Core::System::GetInstance()) == Core::State::Running); } +JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_IsUninitialized(JNIEnv*, + jclass) +{ + return static_cast(Core::IsUninitialized(Core::System::GetInstance()) && + !s_is_booting.IsSet()); +} + JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetVersionString(JNIEnv* env, jclass) { diff --git a/Source/Core/Core/ConfigLoaders/BaseConfigLoader.cpp b/Source/Core/Core/ConfigLoaders/BaseConfigLoader.cpp index 88fa7c0696..81e373b422 100644 --- a/Source/Core/Core/ConfigLoaders/BaseConfigLoader.cpp +++ b/Source/Core/Core/ConfigLoaders/BaseConfigLoader.cpp @@ -33,7 +33,7 @@ namespace ConfigLoaders { void SaveToSYSCONF(Config::LayerType layer, std::function predicate) { - if (Core::IsRunning(Core::System::GetInstance())) + if (!Core::IsUninitialized(Core::System::GetInstance())) return; IOS::HLE::Kernel ios; @@ -183,7 +183,7 @@ public: private: void LoadFromSYSCONF(Config::Layer* layer) { - if (Core::IsRunning(Core::System::GetInstance())) + if (!Core::IsUninitialized(Core::System::GetInstance())) return; IOS::HLE::Kernel ios; diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index 58423377be..90d90c9d18 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -211,6 +211,11 @@ bool IsRunningOrStarting(Core::System& system) return state == State::Running || state == State::Starting; } +bool IsUninitialized(Core::System& system) +{ + return s_state.load() == State::Uninitialized; +} + bool IsCPUThread() { return tls_is_cpu_thread; @@ -237,7 +242,7 @@ bool Init(Core::System& system, std::unique_ptr boot, const Wind { if (s_emu_thread.joinable()) { - if (IsRunning(system)) + if (!IsUninitialized(system)) { PanicAlertFmtT("Emu Thread already running"); return false; diff --git a/Source/Core/Core/Core.h b/Source/Core/Core/Core.h index e6c440566c..cf30cf3866 100644 --- a/Source/Core/Core/Core.h +++ b/Source/Core/Core/Core.h @@ -134,8 +134,13 @@ void UndeclareAsHostThread(); std::string StopMessage(bool main_thread, std::string_view message); +// Returns true when GetState returns Running or Paused. bool IsRunning(Core::System& system); +// Returns true when GetState returns Starting, Running or Paused. bool IsRunningOrStarting(Core::System& system); +// Returns true when GetState returns Uninitialized. +bool IsUninitialized(Core::System& system); + bool IsCPUThread(); // this tells us whether we are the CPU thread. bool IsGPUThread(); bool IsHostThread(); diff --git a/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.cpp b/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.cpp index 5b8a07d24f..c3bbd350f8 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.cpp +++ b/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.cpp @@ -159,6 +159,8 @@ void AchievementSettingsWidget::OnControllerInterfaceConfigure() void AchievementSettingsWidget::LoadSettings() { + Core::System& system = Core::System::GetInstance(); + bool enabled = Config::Get(Config::RA_ENABLED); bool hardcore_enabled = Config::Get(Config::RA_HARDCORE_ENABLED); bool logged_out = Config::Get(Config::RA_API_TOKEN).empty(); @@ -174,18 +176,15 @@ void AchievementSettingsWidget::LoadSettings() SignalBlocking(m_common_password_input)->setVisible(logged_out); SignalBlocking(m_common_password_input)->setEnabled(enabled); SignalBlocking(m_common_login_button)->setVisible(logged_out); - SignalBlocking(m_common_login_button) - ->setEnabled(enabled && !Core::IsRunning(Core::System::GetInstance())); + SignalBlocking(m_common_login_button)->setEnabled(enabled && Core::IsUninitialized(system)); SignalBlocking(m_common_logout_button)->setVisible(!logged_out); SignalBlocking(m_common_logout_button)->setEnabled(enabled); SignalBlocking(m_common_hardcore_enabled_input) ->setChecked(Config::Get(Config::RA_HARDCORE_ENABLED)); - auto& system = Core::System::GetInstance(); SignalBlocking(m_common_hardcore_enabled_input) - ->setEnabled(enabled && - (hardcore_enabled || (Core::GetState(system) == Core::State::Uninitialized && - !system.GetMovie().IsPlayingInput()))); + ->setEnabled(enabled && (hardcore_enabled || (Core::IsUninitialized(system) && + !system.GetMovie().IsPlayingInput()))); SignalBlocking(m_common_unofficial_enabled_input) ->setChecked(Config::Get(Config::RA_UNOFFICIAL_ENABLED)); diff --git a/Source/Core/DolphinQt/CheatSearchFactoryWidget.cpp b/Source/Core/DolphinQt/CheatSearchFactoryWidget.cpp index e1970dacc5..fd713b6695 100644 --- a/Source/Core/DolphinQt/CheatSearchFactoryWidget.cpp +++ b/Source/Core/DolphinQt/CheatSearchFactoryWidget.cpp @@ -159,8 +159,7 @@ void CheatSearchFactoryWidget::OnNewSearchClicked() if (m_standard_address_space->isChecked()) { auto& system = Core::System::GetInstance(); - const Core::State core_state = Core::GetState(system); - if (core_state != Core::State::Running && core_state != Core::State::Paused) + if (!Core::IsRunning(system)) { ModalMessageBox::warning( this, tr("No game running."), diff --git a/Source/Core/DolphinQt/CheatsManager.cpp b/Source/Core/DolphinQt/CheatsManager.cpp index 53f051785c..4fea9120b4 100644 --- a/Source/Core/DolphinQt/CheatsManager.cpp +++ b/Source/Core/DolphinQt/CheatsManager.cpp @@ -104,8 +104,9 @@ void CheatsManager::RefreshCodeTabs(Core::State state, bool force) if (!force && (state == Core::State::Starting || state == Core::State::Stopping)) return; - const auto& game_id = - state != Core::State::Uninitialized ? SConfig::GetInstance().GetGameID() : std::string(); + const auto& game_id = state == Core::State::Running || state == Core::State::Paused ? + SConfig::GetInstance().GetGameID() : + std::string(); const auto& game_tdb_id = SConfig::GetInstance().GetGameTDBID(); const u16 revision = SConfig::GetInstance().GetRevision(); diff --git a/Source/Core/DolphinQt/Config/CheatWarningWidget.cpp b/Source/Core/DolphinQt/Config/CheatWarningWidget.cpp index ee52bf9662..6c3b9638da 100644 --- a/Source/Core/DolphinQt/Config/CheatWarningWidget.cpp +++ b/Source/Core/DolphinQt/Config/CheatWarningWidget.cpp @@ -24,8 +24,9 @@ CheatWarningWidget::CheatWarningWidget(const std::string& game_id, bool restart_ connect(&Settings::Instance(), &Settings::EnableCheatsChanged, this, [this] { Update(Core::IsRunning(Core::System::GetInstance())); }); - connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, - [this](Core::State state) { Update(state == Core::State::Running); }); + connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this](Core::State state) { + Update(state == Core::State::Running || state == Core::State::Paused); + }); Update(Core::IsRunning(Core::System::GetInstance())); } diff --git a/Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.cpp b/Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.cpp index 0d93614021..ccc63fe326 100644 --- a/Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.cpp +++ b/Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.cpp @@ -43,8 +43,7 @@ AdvancedWidget::AdvancedWidget(GraphicsWindow* parent) }); OnBackendChanged(); - OnEmulationStateChanged(Core::GetState(Core::System::GetInstance()) != - Core::State::Uninitialized); + OnEmulationStateChanged(!Core::IsUninitialized(Core::System::GetInstance())); } void AdvancedWidget::CreateWidgets() diff --git a/Source/Core/DolphinQt/Config/Graphics/GeneralWidget.cpp b/Source/Core/DolphinQt/Config/Graphics/GeneralWidget.cpp index 52f09a6f41..3574e6893a 100644 --- a/Source/Core/DolphinQt/Config/Graphics/GeneralWidget.cpp +++ b/Source/Core/DolphinQt/Config/Graphics/GeneralWidget.cpp @@ -44,8 +44,7 @@ GeneralWidget::GeneralWidget(GraphicsWindow* parent) connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this](Core::State state) { OnEmulationStateChanged(state != Core::State::Uninitialized); }); - OnEmulationStateChanged(Core::GetState(Core::System::GetInstance()) != - Core::State::Uninitialized); + OnEmulationStateChanged(!Core::IsUninitialized(Core::System::GetInstance())); } void GeneralWidget::CreateWidgets() @@ -361,7 +360,8 @@ void GeneralWidget::OnBackendChanged(const QString& backend_name) const bool supports_adapters = !adapters.empty(); m_adapter_combo->setCurrentIndex(g_Config.iAdapter); - m_adapter_combo->setEnabled(supports_adapters && !Core::IsRunning(Core::System::GetInstance())); + m_adapter_combo->setEnabled(supports_adapters && + Core::IsUninitialized(Core::System::GetInstance())); static constexpr char TR_ADAPTER_AVAILABLE_DESCRIPTION[] = QT_TR_NOOP("Selects a hardware adapter to use.

" diff --git a/Source/Core/DolphinQt/Debugger/AssemblerWidget.cpp b/Source/Core/DolphinQt/Debugger/AssemblerWidget.cpp index 8dba286c01..fc78b5b613 100644 --- a/Source/Core/DolphinQt/Debugger/AssemblerWidget.cpp +++ b/Source/Core/DolphinQt/Debugger/AssemblerWidget.cpp @@ -791,7 +791,7 @@ bool AssemblerWidget::SaveEditor(AsmEditor* editor) void AssemblerWidget::OnEmulationStateChanged(Core::State state) { - m_inject->setEnabled(state != Core::State::Uninitialized); + m_inject->setEnabled(state == Core::State::Running || state == Core::State::Paused); } void AssemblerWidget::OnTabClose(int index) diff --git a/Source/Core/DolphinQt/Debugger/BreakpointWidget.cpp b/Source/Core/DolphinQt/Debugger/BreakpointWidget.cpp index 130e68e860..1b74cd8ee9 100644 --- a/Source/Core/DolphinQt/Debugger/BreakpointWidget.cpp +++ b/Source/Core/DolphinQt/Debugger/BreakpointWidget.cpp @@ -251,7 +251,7 @@ void BreakpointWidget::UpdateButtonsEnabled() if (!isVisible()) return; - const bool is_initialised = Core::GetState(m_system) != Core::State::Uninitialized; + const bool is_initialised = Core::IsRunning(m_system); m_new->setEnabled(is_initialised); m_load->setEnabled(is_initialised); m_save->setEnabled(is_initialised); diff --git a/Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp b/Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp index 51f2814d9b..7f0e50db74 100644 --- a/Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp +++ b/Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp @@ -560,7 +560,7 @@ void CodeViewWidget::OnContextMenu() QMenu* menu = new QMenu(this); menu->setAttribute(Qt::WA_DeleteOnClose, true); - const bool running = Core::GetState(m_system) != Core::State::Uninitialized; + const bool running = Core::IsRunning(m_system); const bool paused = Core::GetState(m_system) == Core::State::Paused; const u32 addr = GetContextAddress(); diff --git a/Source/Core/DolphinQt/Debugger/ThreadWidget.cpp b/Source/Core/DolphinQt/Debugger/ThreadWidget.cpp index e48097d0e4..55704e31ad 100644 --- a/Source/Core/DolphinQt/Debugger/ThreadWidget.cpp +++ b/Source/Core/DolphinQt/Debugger/ThreadWidget.cpp @@ -258,7 +258,7 @@ void ThreadWidget::Update() auto& system = Core::System::GetInstance(); const auto emu_state = Core::GetState(system); - if (emu_state == Core::State::Stopping) + if (emu_state == Core::State::Stopping || emu_state == Core::State::Uninitialized) { m_thread_table->setRowCount(0); UpdateThreadContext({}); diff --git a/Source/Core/DolphinQt/Debugger/WatchWidget.cpp b/Source/Core/DolphinQt/Debugger/WatchWidget.cpp index 75d3f13ee6..170bfcc792 100644 --- a/Source/Core/DolphinQt/Debugger/WatchWidget.cpp +++ b/Source/Core/DolphinQt/Debugger/WatchWidget.cpp @@ -195,10 +195,11 @@ void WatchWidget::Update() QBrush brush = QPalette().brush(QPalette::Text); - if (!Core::IsRunning(m_system) || !PowerPC::MMU::HostIsRAMAddress(guard, entry.address)) + const bool core_is_running = Core::IsRunning(m_system); + if (!core_is_running || !PowerPC::MMU::HostIsRAMAddress(guard, entry.address)) brush.setColor(Qt::red); - if (Core::IsRunning(m_system)) + if (core_is_running) { if (PowerPC::MMU::HostIsRAMAddress(guard, entry.address)) { diff --git a/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp b/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp index 4d2cadb6ca..30c4b44a86 100644 --- a/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp +++ b/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp @@ -59,11 +59,14 @@ FIFOPlayerWindow::FIFOPlayerWindow(FifoPlayer& fifo_player, FifoRecorder& fifo_r }); connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this](Core::State state) { - if (state == Core::State::Running && m_emu_state != Core::State::Paused) - OnEmulationStarted(); - else if (state == Core::State::Uninitialized) - OnEmulationStopped(); - m_emu_state = state; + if (state != m_emu_state) + { + if (state == Core::State::Running && m_emu_state != Core::State::Paused) + OnEmulationStarted(); + else if (state == Core::State::Uninitialized) + OnEmulationStopped(); + m_emu_state = state; + } }); installEventFilter(this); @@ -376,9 +379,11 @@ void FIFOPlayerWindow::UpdateLimits() void FIFOPlayerWindow::UpdateControls() { - bool running = Core::IsRunning(Core::System::GetInstance()); - bool is_recording = m_fifo_recorder.IsRecording(); - bool is_playing = m_fifo_player.IsPlaying(); + Core::System& system = Core::System::GetInstance(); + const bool core_is_uninitialized = Core::IsUninitialized(system); + const bool core_is_running = Core::IsRunning(system); + const bool is_recording = m_fifo_recorder.IsRecording(); + const bool is_playing = m_fifo_player.IsPlaying(); m_frame_range_from->setEnabled(is_playing); m_frame_range_from_label->setEnabled(is_playing); @@ -394,10 +399,10 @@ void FIFOPlayerWindow::UpdateControls() m_frame_record_count_label->setEnabled(enable_frame_record_count); m_frame_record_count->setEnabled(enable_frame_record_count); - m_load->setEnabled(!running); - m_record->setEnabled(running && !is_playing); + m_load->setEnabled(core_is_uninitialized); + m_record->setEnabled(core_is_running && !is_playing); - m_stop->setVisible(running && is_recording); + m_stop->setVisible(core_is_running && is_recording); m_record->setVisible(!m_stop->isVisible()); m_save->setEnabled(m_fifo_recorder.IsRecordingDone()); diff --git a/Source/Core/DolphinQt/GameList/GameList.cpp b/Source/Core/DolphinQt/GameList/GameList.cpp index 1003cff599..05ca541ef3 100644 --- a/Source/Core/DolphinQt/GameList/GameList.cpp +++ b/Source/Core/DolphinQt/GameList/GameList.cpp @@ -438,7 +438,7 @@ void GameList::ShowContextMenu(const QPoint&) // system menu, trigger a refresh. Settings::Instance().NANDRefresh(); }); - perform_disc_update->setEnabled(!Core::IsRunning(system) || !system.IsWii()); + perform_disc_update->setEnabled(Core::IsUninitialized(system) || !system.IsWii()); } if (!is_mod_descriptor && platform == DiscIO::Platform::WiiWAD) @@ -451,10 +451,10 @@ void GameList::ShowContextMenu(const QPoint&) for (QAction* a : {wad_install_action, wad_uninstall_action}) { - a->setEnabled(!Core::IsRunning(system)); + a->setEnabled(Core::IsUninitialized(system)); menu->addAction(a); } - if (!Core::IsRunning(system)) + if (Core::IsUninitialized(system)) wad_uninstall_action->setEnabled(WiiUtils::IsTitleInstalled(game->GetTitleID())); connect(&Settings::Instance(), &Settings::EmulationStateChanged, menu, @@ -475,8 +475,8 @@ void GameList::ShowContextMenu(const QPoint&) QAction* export_wii_save = menu->addAction(tr("Export Wii Save"), this, &GameList::ExportWiiSave); - open_wii_save_folder->setEnabled(!Core::IsRunning(system)); - export_wii_save->setEnabled(!Core::IsRunning(system)); + open_wii_save_folder->setEnabled(Core::IsUninitialized(system)); + export_wii_save->setEnabled(Core::IsUninitialized(system)); menu->addSeparator(); } @@ -533,7 +533,7 @@ void GameList::ShowContextMenu(const QPoint&) connect(&Settings::Instance(), &Settings::EmulationStateChanged, menu, [=](Core::State state) { netplay_host->setEnabled(state == Core::State::Uninitialized); }); - netplay_host->setEnabled(!Core::IsRunning(system)); + netplay_host->setEnabled(Core::IsUninitialized(system)); menu->addAction(netplay_host); } diff --git a/Source/Core/DolphinQt/HotkeyScheduler.cpp b/Source/Core/DolphinQt/HotkeyScheduler.cpp index 0a6d13e6c0..91ee3c5455 100644 --- a/Source/Core/DolphinQt/HotkeyScheduler.cpp +++ b/Source/Core/DolphinQt/HotkeyScheduler.cpp @@ -188,7 +188,7 @@ void HotkeyScheduler::Run() if (IsHotkey(HK_EXIT)) emit ExitHotkey(); - if (!Core::IsRunning(system)) + if (Core::IsUninitialized(system)) { // Only check for Play Recording hotkey when no game is running if (IsHotkey(HK_PLAY_RECORDING)) diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index f62a7496e7..0bef377f07 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -905,7 +905,7 @@ void MainWindow::OnStopComplete() bool MainWindow::RequestStop() { - if (!Core::IsRunning(Core::System::GetInstance())) + if (Core::IsUninitialized(Core::System::GetInstance())) { Core::QueueHostJob([this](Core::System&) { OnStopComplete(); }, true); return true; @@ -1112,7 +1112,7 @@ void MainWindow::StartGame(std::unique_ptr&& parameters) } // If we're running, only start a new game once we've stopped the last. - if (Core::GetState(Core::System::GetInstance()) != Core::State::Uninitialized) + if (!Core::IsUninitialized(Core::System::GetInstance())) { if (!RequestStop()) return; @@ -1536,7 +1536,7 @@ void MainWindow::NetPlayInit() bool MainWindow::NetPlayJoin() { - if (Core::IsRunning(Core::System::GetInstance())) + if (!Core::IsUninitialized(Core::System::GetInstance())) { ModalMessageBox::critical(nullptr, tr("Error"), tr("Can't start a NetPlay Session while a game is still running!")); @@ -1603,7 +1603,7 @@ bool MainWindow::NetPlayJoin() bool MainWindow::NetPlayHost(const UICommon::GameFile& game) { - if (Core::IsRunning(Core::System::GetInstance())) + if (!Core::IsUninitialized(Core::System::GetInstance())) { ModalMessageBox::critical(nullptr, tr("Error"), tr("Can't start a NetPlay Session while a game is still running!")); @@ -1850,7 +1850,7 @@ void MainWindow::OnImportNANDBackup() result.wait(); - m_menu_bar->UpdateToolsMenu(Core::IsRunning(Core::System::GetInstance())); + m_menu_bar->UpdateToolsMenu(Core::State::Uninitialized); } void MainWindow::OnPlayRecording() @@ -1882,7 +1882,8 @@ void MainWindow::OnStartRecording() { auto& system = Core::System::GetInstance(); auto& movie = system.GetMovie(); - if (Core::GetState(system) == Core::State::Starting || movie.IsRecordingInput() || + if (Core::GetState(system) == Core::State::Starting || + Core::GetState(system) == Core::State::Stopping || movie.IsRecordingInput() || movie.IsPlayingInput()) { return; @@ -1914,7 +1915,7 @@ void MainWindow::OnStartRecording() { emit RecordingStatusChanged(true); - if (!Core::IsRunning(system)) + if (Core::IsUninitialized(system)) Play(); } } diff --git a/Source/Core/DolphinQt/MenuBar.cpp b/Source/Core/DolphinQt/MenuBar.cpp index 75b279db67..b7528272a6 100644 --- a/Source/Core/DolphinQt/MenuBar.cpp +++ b/Source/Core/DolphinQt/MenuBar.cpp @@ -138,9 +138,11 @@ void MenuBar::OnEmulationStateChanged(Core::State state) m_recording_stop->setEnabled(false); m_recording_export->setEnabled(false); } - m_recording_play->setEnabled(m_game_selected && !running); - m_recording_play->setEnabled(m_game_selected && !running && !hardcore); - m_recording_start->setEnabled((m_game_selected || running) && + const bool can_start_from_boot = m_game_selected && state == Core::State::Uninitialized; + const bool can_start_from_savestate = + state == Core::State::Running || state == Core::State::Paused; + m_recording_play->setEnabled(can_start_from_boot && !hardcore); + m_recording_start->setEnabled((can_start_from_boot || can_start_from_savestate) && !Core::System::GetInstance().GetMovie().IsPlayingInput()); // JIT @@ -159,7 +161,7 @@ void MenuBar::OnEmulationStateChanged(Core::State state) m_symbols->setEnabled(running); UpdateStateSlotMenu(); - UpdateToolsMenu(running); + UpdateToolsMenu(state); OnDebugModeToggled(Settings::Instance().IsDebugModeEnabled()); } @@ -300,7 +302,8 @@ void MenuBar::AddToolsMenu() m_boot_sysmenu->setEnabled(false); - connect(&Settings::Instance(), &Settings::NANDRefresh, this, [this] { UpdateToolsMenu(false); }); + connect(&Settings::Instance(), &Settings::NANDRefresh, this, + [this] { UpdateToolsMenu(Core::State::Uninitialized); }); m_perform_online_update_menu = tools_menu->addMenu(tr("Perform Online System Update")); m_perform_online_update_for_current_region = m_perform_online_update_menu->addAction( @@ -1050,20 +1053,23 @@ void MenuBar::AddSymbolsMenu() m_symbols->addAction(tr("&Patch HLE Functions"), this, &MenuBar::PatchHLEFunctions); } -void MenuBar::UpdateToolsMenu(bool emulation_started) +void MenuBar::UpdateToolsMenu(Core::State state) { - m_boot_sysmenu->setEnabled(!emulation_started); - m_perform_online_update_menu->setEnabled(!emulation_started); - m_ntscj_ipl->setEnabled(!emulation_started && File::Exists(Config::GetBootROMPath(JAP_DIR))); - m_ntscu_ipl->setEnabled(!emulation_started && File::Exists(Config::GetBootROMPath(USA_DIR))); - m_pal_ipl->setEnabled(!emulation_started && File::Exists(Config::GetBootROMPath(EUR_DIR))); - m_wad_install_action->setEnabled(!emulation_started); - m_import_backup->setEnabled(!emulation_started); - m_check_nand->setEnabled(!emulation_started); - m_import_wii_save->setEnabled(!emulation_started); - m_export_wii_saves->setEnabled(!emulation_started); + const bool is_uninitialized = state == Core::State::Uninitialized; + const bool is_running = state == Core::State::Running || state == Core::State::Paused; - if (!emulation_started) + m_boot_sysmenu->setEnabled(is_uninitialized); + m_perform_online_update_menu->setEnabled(is_uninitialized); + m_ntscj_ipl->setEnabled(is_uninitialized && File::Exists(Config::GetBootROMPath(JAP_DIR))); + m_ntscu_ipl->setEnabled(is_uninitialized && File::Exists(Config::GetBootROMPath(USA_DIR))); + m_pal_ipl->setEnabled(is_uninitialized && File::Exists(Config::GetBootROMPath(EUR_DIR))); + m_wad_install_action->setEnabled(is_uninitialized); + m_import_backup->setEnabled(is_uninitialized); + m_check_nand->setEnabled(is_uninitialized); + m_import_wii_save->setEnabled(is_uninitialized); + m_export_wii_saves->setEnabled(is_uninitialized); + + if (is_uninitialized) { IOS::HLE::Kernel ios; const auto tmd = ios.GetESCore().FindInstalledTMD(Titles::SYSTEM_MENU); @@ -1086,7 +1092,7 @@ void MenuBar::UpdateToolsMenu(bool emulation_started) } const auto bt = WiiUtils::GetBluetoothEmuDevice(); - const bool enable_wiimotes = emulation_started && bt != nullptr; + const bool enable_wiimotes = is_running && bt != nullptr; for (std::size_t i = 0; i < m_wii_remotes.size(); i++) { @@ -1257,16 +1263,20 @@ void MenuBar::OnSelectionChanged(std::shared_ptr game_ m_game_selected = !!game_file; auto& system = Core::System::GetInstance(); - const bool core_is_running = Core::IsRunning(system); - m_recording_play->setEnabled(m_game_selected && !core_is_running); - m_recording_start->setEnabled((m_game_selected || core_is_running) && + const bool can_start_from_boot = m_game_selected && Core::IsUninitialized(system); + const bool can_start_from_savestate = Core::IsRunning(system); + m_recording_play->setEnabled(can_start_from_boot); + m_recording_start->setEnabled((can_start_from_boot || can_start_from_savestate) && !system.GetMovie().IsPlayingInput()); } void MenuBar::OnRecordingStatusChanged(bool recording) { auto& system = Core::System::GetInstance(); - m_recording_start->setEnabled(!recording && (m_game_selected || Core::IsRunning(system))); + const bool can_start_from_boot = m_game_selected && Core::IsUninitialized(system); + const bool can_start_from_savestate = Core::IsRunning(system); + + m_recording_start->setEnabled(!recording && (can_start_from_boot || can_start_from_savestate)); m_recording_stop->setEnabled(recording); m_recording_export->setEnabled(recording); } diff --git a/Source/Core/DolphinQt/MenuBar.h b/Source/Core/DolphinQt/MenuBar.h index b6620291d2..538ca29bb5 100644 --- a/Source/Core/DolphinQt/MenuBar.h +++ b/Source/Core/DolphinQt/MenuBar.h @@ -43,7 +43,7 @@ public: explicit MenuBar(QWidget* parent = nullptr); - void UpdateToolsMenu(bool emulation_started); + void UpdateToolsMenu(Core::State state); QMenu* GetListColumnsMenu() const { return m_cols_menu; } diff --git a/Source/Core/DolphinQt/NetPlay/NetPlayDialog.cpp b/Source/Core/DolphinQt/NetPlay/NetPlayDialog.cpp index 4ae4b5f315..2bbf52d11d 100644 --- a/Source/Core/DolphinQt/NetPlay/NetPlayDialog.cpp +++ b/Source/Core/DolphinQt/NetPlay/NetPlayDialog.cpp @@ -804,9 +804,11 @@ void NetPlayDialog::DisplayMessage(const QString& msg, const std::string& color, QColor c(color.empty() ? QStringLiteral("white") : QString::fromStdString(color)); if (g_ActiveConfig.bShowNetPlayMessages && Core::IsRunning(Core::System::GetInstance())) + { g_netplay_chat_ui->AppendChat(msg.toStdString(), {static_cast(c.redF()), static_cast(c.greenF()), static_cast(c.blueF())}); + } } void NetPlayDialog::AppendChat(const std::string& msg) diff --git a/Source/Core/DolphinQt/Settings/AdvancedPane.cpp b/Source/Core/DolphinQt/Settings/AdvancedPane.cpp index 9aaef7be2d..2f4c163674 100644 --- a/Source/Core/DolphinQt/Settings/AdvancedPane.cpp +++ b/Source/Core/DolphinQt/Settings/AdvancedPane.cpp @@ -240,7 +240,7 @@ void AdvancedPane::ConnectLayout() void AdvancedPane::Update() { - const bool running = Core::GetState(Core::System::GetInstance()) != Core::State::Uninitialized; + const bool running = !Core::IsUninitialized(Core::System::GetInstance()); const bool enable_cpu_clock_override_widgets = Config::Get(Config::MAIN_OVERCLOCK_ENABLE); const bool enable_ram_override_widgets = Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE); const bool enable_custom_rtc_widgets = Config::Get(Config::MAIN_CUSTOM_RTC_ENABLE) && !running; diff --git a/Source/Core/DolphinQt/Settings/AudioPane.cpp b/Source/Core/DolphinQt/Settings/AudioPane.cpp index 289dc28e7d..d2290025ed 100644 --- a/Source/Core/DolphinQt/Settings/AudioPane.cpp +++ b/Source/Core/DolphinQt/Settings/AudioPane.cpp @@ -40,8 +40,7 @@ AudioPane::AudioPane() OnEmulationStateChanged(state != Core::State::Uninitialized); }); - OnEmulationStateChanged(Core::GetState(Core::System::GetInstance()) != - Core::State::Uninitialized); + OnEmulationStateChanged(!Core::IsUninitialized(Core::System::GetInstance())); } void AudioPane::CreateWidgets() diff --git a/Source/Core/DolphinQt/Settings/WiiPane.cpp b/Source/Core/DolphinQt/Settings/WiiPane.cpp index b6ad36654f..0e432855af 100644 --- a/Source/Core/DolphinQt/Settings/WiiPane.cpp +++ b/Source/Core/DolphinQt/Settings/WiiPane.cpp @@ -93,8 +93,7 @@ WiiPane::WiiPane(QWidget* parent) : QWidget(parent) LoadConfig(); ConnectLayout(); ValidateSelectionState(); - OnEmulationStateChanged(Core::GetState(Core::System::GetInstance()) != - Core::State::Uninitialized); + OnEmulationStateChanged(!Core::IsUninitialized(Core::System::GetInstance())); } void WiiPane::CreateLayout() diff --git a/Source/Core/VideoCommon/VideoConfig.cpp b/Source/Core/VideoCommon/VideoConfig.cpp index efa159795c..0e2e3566ea 100644 --- a/Source/Core/VideoCommon/VideoConfig.cpp +++ b/Source/Core/VideoCommon/VideoConfig.cpp @@ -66,15 +66,12 @@ void VideoConfig::Refresh() CPUThreadConfigCallback::AddConfigChangedCallback([]() { auto& system = Core::System::GetInstance(); - const bool lock_gpu_thread = Core::IsRunning(system); - if (lock_gpu_thread) - system.GetFifo().PauseAndLock(true, false); + system.GetFifo().PauseAndLock(true, false); g_Config.Refresh(); g_Config.VerifyValidity(); - if (lock_gpu_thread) - system.GetFifo().PauseAndLock(false, true); + system.GetFifo().PauseAndLock(false, true); }); s_has_registered_callback = true; }