summaryrefslogtreecommitdiff
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/Core/Common/Config/Config.h3
-rw-r--r--Source/Core/Core/CMakeLists.txt2
-rw-r--r--Source/Core/Core/CPUThreadConfigCallback.cpp76
-rw-r--r--Source/Core/Core/CPUThreadConfigCallback.h22
-rw-r--r--Source/Core/Core/Core.cpp4
-rw-r--r--Source/Core/Core/CoreTiming.cpp13
-rw-r--r--Source/Core/Core/FreeLookConfig.cpp4
-rw-r--r--Source/Core/Core/HW/CPU.cpp3
-rw-r--r--Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp19
-rw-r--r--Source/Core/Core/PowerPC/JitCommon/JitBase.cpp8
-rw-r--r--Source/Core/DolphinLib.props2
-rw-r--r--Source/Core/VideoCommon/VideoConfig.cpp25
12 files changed, 152 insertions, 29 deletions
diff --git a/Source/Core/Common/Config/Config.h b/Source/Core/Common/Config/Config.h
index b448f234f9..4d770ee36e 100644
--- a/Source/Core/Common/Config/Config.h
+++ b/Source/Core/Common/Config/Config.h
@@ -22,7 +22,8 @@ void AddLayer(std::unique_ptr<ConfigLayerLoader> loader);
std::shared_ptr<Layer> GetLayer(LayerType layer);
void RemoveLayer(LayerType layer);
-// returns an ID that can be passed to RemoveConfigChangedCallback()
+// Returns an ID that can be passed to RemoveConfigChangedCallback().
+// The callback may be called from any thread.
size_t AddConfigChangedCallback(ConfigChangedCallback func);
void RemoveConfigChangedCallback(size_t callback_id);
void OnConfigChanged();
diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt
index f50185049a..40d02136c5 100644
--- a/Source/Core/Core/CMakeLists.txt
+++ b/Source/Core/Core/CMakeLists.txt
@@ -59,6 +59,8 @@ add_library(core
Core.h
CoreTiming.cpp
CoreTiming.h
+ CPUThreadConfigCallback.cpp
+ CPUThreadConfigCallback.h
Debugger/CodeTrace.cpp
Debugger/CodeTrace.h
Debugger/DebugInterface.h
diff --git a/Source/Core/Core/CPUThreadConfigCallback.cpp b/Source/Core/Core/CPUThreadConfigCallback.cpp
new file mode 100644
index 0000000000..2148630c22
--- /dev/null
+++ b/Source/Core/Core/CPUThreadConfigCallback.cpp
@@ -0,0 +1,76 @@
+// Copyright 2023 Dolphin Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "Core/CPUThreadConfigCallback.h"
+
+#include <atomic>
+
+#include "Common/Assert.h"
+#include "Common/Config/Config.h"
+#include "Core/Core.h"
+
+namespace
+{
+std::atomic<bool> s_should_run_callbacks = false;
+
+static std::vector<std::pair<size_t, Config::ConfigChangedCallback>> s_callbacks;
+static size_t s_next_callback_id = 0;
+
+void RunCallbacks()
+{
+ for (const auto& callback : s_callbacks)
+ callback.second();
+}
+
+void OnConfigChanged()
+{
+ if (Core::IsCPUThread())
+ {
+ s_should_run_callbacks.store(false, std::memory_order_relaxed);
+ RunCallbacks();
+ }
+ else
+ {
+ s_should_run_callbacks.store(true, std::memory_order_relaxed);
+ }
+}
+
+}; // namespace
+
+namespace CPUThreadConfigCallback
+{
+size_t AddConfigChangedCallback(Config::ConfigChangedCallback func)
+{
+ DEBUG_ASSERT(Core::IsCPUThread());
+
+ static size_t s_config_changed_callback_id = Config::AddConfigChangedCallback(&OnConfigChanged);
+
+ const size_t callback_id = s_next_callback_id;
+ ++s_next_callback_id;
+ s_callbacks.emplace_back(std::make_pair(callback_id, std::move(func)));
+ return callback_id;
+}
+
+void RemoveConfigChangedCallback(size_t callback_id)
+{
+ DEBUG_ASSERT(Core::IsCPUThread());
+
+ for (auto it = s_callbacks.begin(); it != s_callbacks.end(); ++it)
+ {
+ if (it->first == callback_id)
+ {
+ s_callbacks.erase(it);
+ return;
+ }
+ }
+}
+
+void CheckForConfigChanges()
+{
+ DEBUG_ASSERT(Core::IsCPUThread());
+
+ if (s_should_run_callbacks.exchange(false, std::memory_order_relaxed))
+ RunCallbacks();
+}
+
+}; // namespace CPUThreadConfigCallback
diff --git a/Source/Core/Core/CPUThreadConfigCallback.h b/Source/Core/Core/CPUThreadConfigCallback.h
new file mode 100644
index 0000000000..c43e01a9a0
--- /dev/null
+++ b/Source/Core/Core/CPUThreadConfigCallback.h
@@ -0,0 +1,22 @@
+// Copyright 2023 Dolphin Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "Common/Config/Config.h"
+
+// This file lets you register callbacks like in Common/Config/Config.h, with the difference that
+// callbacks registered here are guaranteed to run on the CPU thread. Callbacks registered here may
+// run with a slight delay compared to regular config callbacks.
+
+namespace CPUThreadConfigCallback
+{
+// returns an ID that can be passed to RemoveConfigChangedCallback()
+size_t AddConfigChangedCallback(Config::ConfigChangedCallback func);
+
+void RemoveConfigChangedCallback(size_t callback_id);
+
+// Should be called regularly from the CPU thread
+void CheckForConfigChanges();
+
+}; // namespace CPUThreadConfigCallback
diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp
index 2865c81a9d..0fc7db59dd 100644
--- a/Source/Core/Core/Core.cpp
+++ b/Source/Core/Core/Core.cpp
@@ -41,6 +41,7 @@
#include "Core/AchievementManager.h"
#include "Core/Boot/Boot.h"
#include "Core/BootManager.h"
+#include "Core/CPUThreadConfigCallback.h"
#include "Core/Config/MainSettings.h"
#include "Core/ConfigManager.h"
#include "Core/CoreTiming.h"
@@ -511,6 +512,9 @@ static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi
DeclareAsCPUThread();
s_frame_step = false;
+ // If settings have changed since the previous run, notify callbacks.
+ CPUThreadConfigCallback::CheckForConfigChanges();
+
// Switch the window used for inputs to the render window. This way, the cursor position
// is relative to the render window, instead of the main window.
ASSERT(g_controller_interface.IsInit());
diff --git a/Source/Core/Core/CoreTiming.cpp b/Source/Core/Core/CoreTiming.cpp
index 8e5d489a58..2e6f6a0968 100644
--- a/Source/Core/Core/CoreTiming.cpp
+++ b/Source/Core/Core/CoreTiming.cpp
@@ -16,6 +16,7 @@
#include "Common/Logging/Log.h"
#include "Common/SPSCQueue.h"
+#include "Core/CPUThreadConfigCallback.h"
#include "Core/Config/MainSettings.h"
#include "Core/Core.h"
#include "Core/PowerPC/PowerPC.h"
@@ -88,8 +89,8 @@ void CoreTimingManager::UnregisterAllEvents()
void CoreTimingManager::Init()
{
- m_registered_config_callback_id = Config::AddConfigChangedCallback(
- [this]() { Core::RunAsCPUThread([this]() { RefreshConfig(); }); });
+ m_registered_config_callback_id =
+ CPUThreadConfigCallback::AddConfigChangedCallback([this]() { RefreshConfig(); });
RefreshConfig();
m_last_oc_factor = m_config_oc_factor;
@@ -118,7 +119,7 @@ void CoreTimingManager::Shutdown()
MoveEvents();
ClearPendingEvents();
UnregisterAllEvents();
- Config::RemoveConfigChangedCallback(m_registered_config_callback_id);
+ CPUThreadConfigCallback::RemoveConfigChangedCallback(m_registered_config_callback_id);
}
void CoreTimingManager::RefreshConfig()
@@ -311,11 +312,13 @@ void CoreTimingManager::MoveEvents()
void CoreTimingManager::Advance()
{
- auto& power_pc = m_system.GetPowerPC();
- auto& ppc_state = power_pc.GetPPCState();
+ CPUThreadConfigCallback::CheckForConfigChanges();
MoveEvents();
+ auto& power_pc = m_system.GetPowerPC();
+ auto& ppc_state = power_pc.GetPPCState();
+
int cyclesExecuted = m_globals.slice_length - DowncountToCycles(ppc_state.downcount);
m_globals.global_timer += cyclesExecuted;
m_last_oc_factor = m_config_oc_factor;
diff --git a/Source/Core/Core/FreeLookConfig.cpp b/Source/Core/Core/FreeLookConfig.cpp
index 4f9ca377a1..31a673ce85 100644
--- a/Source/Core/Core/FreeLookConfig.cpp
+++ b/Source/Core/Core/FreeLookConfig.cpp
@@ -2,6 +2,8 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "Core/FreeLookConfig.h"
+
+#include "Core/CPUThreadConfigCallback.h"
#include "Core/Config/FreeLookSettings.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
@@ -37,7 +39,7 @@ void Config::Refresh()
{
if (!s_has_registered_callback)
{
- ::Config::AddConfigChangedCallback([] { Core::RunAsCPUThread([] { s_config.Refresh(); }); });
+ CPUThreadConfigCallback::AddConfigChangedCallback([] { s_config.Refresh(); });
s_has_registered_callback = true;
}
diff --git a/Source/Core/Core/HW/CPU.cpp b/Source/Core/Core/HW/CPU.cpp
index aa90ab54d2..8a9634d527 100644
--- a/Source/Core/Core/HW/CPU.cpp
+++ b/Source/Core/Core/HW/CPU.cpp
@@ -10,6 +10,7 @@
#include "AudioCommon/AudioCommon.h"
#include "Common/CommonTypes.h"
#include "Common/Event.h"
+#include "Core/CPUThreadConfigCallback.h"
#include "Core/Core.h"
#include "Core/Host.h"
#include "Core/PowerPC/GDBStub.h"
@@ -75,6 +76,7 @@ void CPUManager::Run()
{
m_state_cpu_cvar.wait(state_lock, [this] { return !m_state_paused_and_locked; });
ExecutePendingJobs(state_lock);
+ CPUThreadConfigCallback::CheckForConfigChanges();
Common::Event gdb_step_sync_event;
switch (m_state)
@@ -113,6 +115,7 @@ void CPUManager::Run()
// Wait for step command.
m_state_cpu_cvar.wait(state_lock, [this, &state_lock, &gdb_step_sync_event] {
ExecutePendingJobs(state_lock);
+ CPUThreadConfigCallback::CheckForConfigChanges();
state_lock.unlock();
if (GDBStub::IsActive() && GDBStub::HasControl())
{
diff --git a/Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp b/Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp
index 55ee8e771b..6339ec087a 100644
--- a/Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp
+++ b/Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp
@@ -15,6 +15,7 @@
#include "Common/Logging/Log.h"
#include "Common/SDCardUtil.h"
+#include "Core/CPUThreadConfigCallback.h"
#include "Core/Config/MainSettings.h"
#include "Core/Config/SessionSettings.h"
#include "Core/Core.h"
@@ -32,27 +33,23 @@ SDIOSlot0Device::SDIOSlot0Device(EmulationKernel& ios, const std::string& device
if (!Config::Get(Config::MAIN_ALLOW_SD_WRITES))
INFO_LOG_FMT(IOS_SD, "Writes to SD card disabled by user");
- m_config_callback_id = Config::AddConfigChangedCallback([this] { RefreshConfig(); });
+ m_config_callback_id =
+ CPUThreadConfigCallback::AddConfigChangedCallback([this] { RefreshConfig(); });
m_sd_card_inserted = Config::Get(Config::MAIN_WII_SD_CARD);
}
SDIOSlot0Device::~SDIOSlot0Device()
{
- Config::RemoveConfigChangedCallback(m_config_callback_id);
+ CPUThreadConfigCallback::RemoveConfigChangedCallback(m_config_callback_id);
}
void SDIOSlot0Device::RefreshConfig()
{
- if (m_sd_card_inserted != Config::Get(Config::MAIN_WII_SD_CARD))
+ const bool sd_card_inserted = Config::Get(Config::MAIN_WII_SD_CARD);
+ if (m_sd_card_inserted != sd_card_inserted)
{
- Core::RunAsCPUThread([this] {
- const bool sd_card_inserted = Config::Get(Config::MAIN_WII_SD_CARD);
- if (m_sd_card_inserted != sd_card_inserted)
- {
- m_sd_card_inserted = sd_card_inserted;
- EventNotify();
- }
- });
+ m_sd_card_inserted = sd_card_inserted;
+ EventNotify();
}
}
diff --git a/Source/Core/Core/PowerPC/JitCommon/JitBase.cpp b/Source/Core/Core/PowerPC/JitCommon/JitBase.cpp
index 887e73a402..17d9fe1bea 100644
--- a/Source/Core/Core/PowerPC/JitCommon/JitBase.cpp
+++ b/Source/Core/Core/PowerPC/JitCommon/JitBase.cpp
@@ -7,6 +7,8 @@
#include "Common/CommonTypes.h"
#include "Common/MemoryUtil.h"
#include "Common/Thread.h"
+
+#include "Core/CPUThreadConfigCallback.h"
#include "Core/Config/MainSettings.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
@@ -64,14 +66,14 @@ JitBase::JitBase(Core::System& system)
: m_code_buffer(code_buffer_size), m_system(system), m_ppc_state(system.GetPPCState()),
m_mmu(system.GetMMU())
{
- m_registered_config_callback_id = Config::AddConfigChangedCallback(
- [this] { Core::RunAsCPUThread([this] { RefreshConfig(); }); });
+ m_registered_config_callback_id =
+ CPUThreadConfigCallback::AddConfigChangedCallback([this] { RefreshConfig(); });
RefreshConfig();
}
JitBase::~JitBase()
{
- Config::RemoveConfigChangedCallback(m_registered_config_callback_id);
+ CPUThreadConfigCallback::RemoveConfigChangedCallback(m_registered_config_callback_id);
}
void JitBase::RefreshConfig()
diff --git a/Source/Core/DolphinLib.props b/Source/Core/DolphinLib.props
index 1b44f15ec4..882471aabf 100644
--- a/Source/Core/DolphinLib.props
+++ b/Source/Core/DolphinLib.props
@@ -190,6 +190,7 @@
<ClInclude Include="Core\ConfigManager.h" />
<ClInclude Include="Core\Core.h" />
<ClInclude Include="Core\CoreTiming.h" />
+ <ClInclude Include="Core\CPUThreadConfigCallback.h" />
<ClInclude Include="Core\Debugger\CodeTrace.h" />
<ClInclude Include="Core\Debugger\DebugInterface.h" />
<ClInclude Include="Core\Debugger\Debugger_SymbolMap.h" />
@@ -833,6 +834,7 @@
<ClCompile Include="Core\ConfigManager.cpp" />
<ClCompile Include="Core\Core.cpp" />
<ClCompile Include="Core\CoreTiming.cpp" />
+ <ClCompile Include="Core\CPUThreadConfigCallback.cpp" />
<ClCompile Include="Core\Debugger\CodeTrace.cpp" />
<ClCompile Include="Core\Debugger\Debugger_SymbolMap.cpp" />
<ClCompile Include="Core\Debugger\Dump.cpp" />
diff --git a/Source/Core/VideoCommon/VideoConfig.cpp b/Source/Core/VideoCommon/VideoConfig.cpp
index 42bf178047..b00976b9b4 100644
--- a/Source/Core/VideoCommon/VideoConfig.cpp
+++ b/Source/Core/VideoCommon/VideoConfig.cpp
@@ -9,6 +9,7 @@
#include "Common/CommonTypes.h"
#include "Common/StringUtil.h"
+#include "Core/CPUThreadConfigCallback.h"
#include "Core/Config/GraphicsSettings.h"
#include "Core/Config/MainSettings.h"
#include "Core/ConfigManager.h"
@@ -19,6 +20,7 @@
#include "VideoCommon/AbstractGfx.h"
#include "VideoCommon/BPFunctions.h"
#include "VideoCommon/DriverDetails.h"
+#include "VideoCommon/Fifo.h"
#include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/FreeLookCamera.h"
#include "VideoCommon/GraphicsModSystem/Config/GraphicsMod.h"
@@ -57,14 +59,21 @@ void VideoConfig::Refresh()
{
// There was a race condition between the video thread and the host thread here, if
// corrections need to be made by VerifyValidity(). Briefly, the config will contain
- // invalid values. Instead, pause emulation first, which will flush the video thread,
- // update the config and correct it, then resume emulation, after which the video
- // thread will detect the config has changed and act accordingly.
- Config::AddConfigChangedCallback([]() {
- Core::RunAsCPUThread([]() {
- g_Config.Refresh();
- g_Config.VerifyValidity();
- });
+ // invalid values. Instead, pause the video thread first, update the config and correct
+ // it, then resume emulation, after which the video thread will detect the config has
+ // changed and act accordingly.
+ CPUThreadConfigCallback::AddConfigChangedCallback([]() {
+ auto& system = Core::System::GetInstance();
+
+ const bool lock_gpu_thread = Core::IsRunningAndStarted();
+ if (lock_gpu_thread)
+ system.GetFifo().PauseAndLock(system, true, false);
+
+ g_Config.Refresh();
+ g_Config.VerifyValidity();
+
+ if (lock_gpu_thread)
+ system.GetFifo().PauseAndLock(system, false, true);
});
s_has_registered_callback = true;
}