From e403dee3da641522b1ee23829c720a8ccb8c7631 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Sun, 27 Apr 2025 19:52:42 -0500 Subject: [PATCH 1/3] Common: Add MoveOnlyFunction. --- Source/Core/Common/CMakeLists.txt | 1 + Source/Core/Common/Functional.h | 51 +++++++++++++++++++++++++++++++ Source/Core/DolphinLib.props | 1 + 3 files changed, 53 insertions(+) create mode 100644 Source/Core/Common/Functional.h diff --git a/Source/Core/Common/CMakeLists.txt b/Source/Core/Common/CMakeLists.txt index 608e2f270a..aca142b9cd 100644 --- a/Source/Core/Common/CMakeLists.txt +++ b/Source/Core/Common/CMakeLists.txt @@ -70,6 +70,7 @@ add_library(common Flag.h FloatUtils.cpp FloatUtils.h + Functional.h FormatUtil.h FPURoundMode.h GekkoDisassembler.cpp diff --git a/Source/Core/Common/Functional.h b/Source/Core/Common/Functional.h new file mode 100644 index 0000000000..49d81d5a24 --- /dev/null +++ b/Source/Core/Common/Functional.h @@ -0,0 +1,51 @@ +// Copyright 2025 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +// TODO C++23: Replace with std::move_only_function. + +namespace Common +{ + +template +class MoveOnlyFunction; + +template +class MoveOnlyFunction +{ +public: + using result_type = R; + + MoveOnlyFunction() = default; + + template + MoveOnlyFunction(F&& f) : m_ptr{std::make_unique>(std::forward(f))} + { + } + + result_type operator()(Args... args) const { return m_ptr->Invoke(std::forward(args)...); } + explicit operator bool() const { return m_ptr != nullptr; }; + void swap(MoveOnlyFunction& other) { m_ptr.swap(other.m_ptr); } + +private: + struct FuncBase + { + virtual ~FuncBase() = default; + virtual result_type Invoke(Args...) = 0; + }; + + template + struct Func : FuncBase + { + Func(F&& f) : func{std::forward(f)} {} + result_type Invoke(Args... args) override { return func(std::forward(args)...); } + F func; + }; + + std::unique_ptr m_ptr; +}; + +} // namespace Common diff --git a/Source/Core/DolphinLib.props b/Source/Core/DolphinLib.props index 8b5e3b9f00..57d0465959 100644 --- a/Source/Core/DolphinLib.props +++ b/Source/Core/DolphinLib.props @@ -62,6 +62,7 @@ + From 37aa65afc4190e1966215151923d3432011e100b Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Sun, 27 Apr 2025 19:53:18 -0500 Subject: [PATCH 2/3] VideoCommon: Use MoveOnlyFunction for AsyncRequests. --- Source/Core/VideoCommon/AsyncRequests.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/Core/VideoCommon/AsyncRequests.h b/Source/Core/VideoCommon/AsyncRequests.h index ad2a120e8b..1c72b55b85 100644 --- a/Source/Core/VideoCommon/AsyncRequests.h +++ b/Source/Core/VideoCommon/AsyncRequests.h @@ -10,6 +10,7 @@ #include #include "Common/Flag.h" +#include "Common/Functional.h" struct EfbPokeData; class PointerWrap; @@ -60,7 +61,7 @@ public: static AsyncRequests* GetInstance() { return &s_singleton; } private: - using Event = std::function; + using Event = Common::MoveOnlyFunction; void QueueEvent(Event&& event); From 4ec2072bebd40458b1a65399af30a72afd737d03 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Sun, 27 Apr 2025 19:53:20 -0500 Subject: [PATCH 3/3] Core: Use MoveOnlyFunction for RunOnCPUThread. --- Source/Core/Core/Core.cpp | 3 ++- Source/Core/Core/Core.h | 4 +++- Source/Core/Core/HW/CPU.cpp | 4 ++-- Source/Core/Core/HW/CPU.h | 6 +++--- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index 5f90f93bae..424b364795 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -809,7 +809,8 @@ static bool PauseAndLock(Core::System& system, bool do_lock, bool unpause_on_unl return was_unpaused; } -void RunOnCPUThread(Core::System& system, std::function function, bool wait_for_completion) +void RunOnCPUThread(Core::System& system, Common::MoveOnlyFunction function, + bool wait_for_completion) { // If the CPU thread is not running, assume there is no active CPU thread we can race against. if (!IsRunning(system) || IsCPUThread()) diff --git a/Source/Core/Core/Core.h b/Source/Core/Core/Core.h index eca18cf3be..188f57a75a 100644 --- a/Source/Core/Core/Core.h +++ b/Source/Core/Core/Core.h @@ -15,6 +15,7 @@ #include #include "Common/CommonTypes.h" +#include "Common/Functional.h" struct BootParameters; struct WindowSystemInfo; @@ -159,7 +160,8 @@ void OnFrameEnd(Core::System& system); // Run a function on the CPU thread, asynchronously. // This is only valid to call from the host thread, since it uses PauseAndLock() internally. -void RunOnCPUThread(Core::System& system, std::function function, bool wait_for_completion); +void RunOnCPUThread(Core::System& system, Common::MoveOnlyFunction function, + bool wait_for_completion); // for calling back into UI code without introducing a dependency on it in core using StateChangedCallbackFunc = std::function; diff --git a/Source/Core/Core/HW/CPU.cpp b/Source/Core/Core/HW/CPU.cpp index 5a21e5e3c8..e67111e72d 100644 --- a/Source/Core/Core/HW/CPU.cpp +++ b/Source/Core/Core/HW/CPU.cpp @@ -60,7 +60,7 @@ void CPUManager::ExecutePendingJobs(std::unique_lock& state_lock) { while (!m_pending_jobs.empty()) { - auto callback = m_pending_jobs.front(); + auto callback = std::move(m_pending_jobs.front()); m_pending_jobs.pop(); state_lock.unlock(); callback(); @@ -414,7 +414,7 @@ bool CPUManager::PauseAndLock(bool do_lock, bool unpause_on_unlock, bool control return was_unpaused; } -void CPUManager::AddCPUThreadJob(std::function function) +void CPUManager::AddCPUThreadJob(Common::MoveOnlyFunction function) { std::unique_lock state_lock(m_state_change_lock); m_pending_jobs.push(std::move(function)); diff --git a/Source/Core/Core/HW/CPU.h b/Source/Core/Core/HW/CPU.h index b73471136d..438a48763b 100644 --- a/Source/Core/Core/HW/CPU.h +++ b/Source/Core/Core/HW/CPU.h @@ -4,11 +4,11 @@ #pragma once #include -#include #include #include #include "Common/Event.h" +#include "Common/Functional.h" namespace Common { @@ -99,7 +99,7 @@ public: // Adds a job to be executed during on the CPU thread. This should be combined with // PauseAndLock(), as while the CPU is in the run loop, it won't execute the function. - void AddCPUThreadJob(std::function function); + void AddCPUThreadJob(Common::MoveOnlyFunction function); private: void FlushStepSyncEventLocked(); @@ -135,7 +135,7 @@ private: bool m_state_system_request_stepping = false; bool m_state_cpu_step_instruction = false; Common::Event* m_state_cpu_step_instruction_sync = nullptr; - std::queue> m_pending_jobs; + std::queue> m_pending_jobs; Common::Event m_time_played_finish_sync; Core::System& m_system;