From 252ec7452c4c908537036215c1888f5c5d596bd7 Mon Sep 17 00:00:00 2001 From: Dentomologist Date: Sat, 7 Mar 2026 12:33:39 -0800 Subject: [PATCH] PerformanceMetrics: Use HookableEvent for state changed callback Use the normal state changed `HookableEvent` instead of having `Core::NotifyStateChanged` call `g_perf_metrics.OnEmulationStateChanged` directly. The direct call was added in bad78cfed416d89ceb6b0acf6c134d3691b3d624 to avoid a crash. At the time state changed callbacks were stored in a vector, and the crash was caused by `g_perf_metric`'s destructor trying to remove the callback from the already-destroyed vector. Later a97627e736ff352e031123519c799e65cc98b32c switched state changed callbacks to use `HookableEvent`, which is specifically designed to handle the case where a hook outlives its associated event. Since the workaround is no longer necessary replace it with a standard `EventHook`. --- Source/Core/Core/Core.cpp | 3 +-- Source/Core/VideoCommon/PerformanceMetrics.cpp | 17 +++++++++++------ Source/Core/VideoCommon/PerformanceMetrics.h | 7 ++++--- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index bdae112865..8ee7c44c2b 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -929,10 +929,9 @@ Common::EventHook AddOnStateChangedCallback(StateChangedCallbackFunc callback) return s_state_changed_event.Register(std::move(callback)); } -void NotifyStateChanged(Core::State state) +void NotifyStateChanged(const Core::State state) { s_state_changed_event.Trigger(state); - g_perf_metrics.OnEmulationStateChanged(state); } void UpdateWantDeterminism(Core::System& system, bool initial) diff --git a/Source/Core/VideoCommon/PerformanceMetrics.cpp b/Source/Core/VideoCommon/PerformanceMetrics.cpp index 0e2e371d4e..cba4beb8c6 100644 --- a/Source/Core/VideoCommon/PerformanceMetrics.cpp +++ b/Source/Core/VideoCommon/PerformanceMetrics.cpp @@ -8,11 +8,22 @@ #include #include +#include "Common/HookableEvent.h" #include "Core/Config/GraphicsSettings.h" +#include "Core/Core.h" #include "VideoCommon/VideoConfig.h" PerformanceMetrics g_perf_metrics; +PerformanceMetrics::PerformanceMetrics() +{ + const auto invalidate_counters_last_time = [this](Core::State) { + m_fps_counter.InvalidateLastTime(); + m_vps_counter.InvalidateLastTime(); + }; + m_state_change_hook = Core::AddOnStateChangedCallback(invalidate_counters_last_time); +} + void PerformanceMetrics::Reset() { m_fps_counter.Reset(); @@ -37,12 +48,6 @@ void PerformanceMetrics::CountVBlank() m_vps_counter.Count(); } -void PerformanceMetrics::OnEmulationStateChanged([[maybe_unused]] Core::State state) -{ - m_fps_counter.InvalidateLastTime(); - m_vps_counter.InvalidateLastTime(); -} - void PerformanceMetrics::CountThrottleSleep(DT sleep) { m_time_sleeping += sleep; diff --git a/Source/Core/VideoCommon/PerformanceMetrics.h b/Source/Core/VideoCommon/PerformanceMetrics.h index 914e6bc82f..71fd339c07 100644 --- a/Source/Core/VideoCommon/PerformanceMetrics.h +++ b/Source/Core/VideoCommon/PerformanceMetrics.h @@ -7,7 +7,7 @@ #include #include "Common/CommonTypes.h" -#include "Core/Core.h" +#include "Common/HookableEvent.h" #include "VideoCommon/PerformanceTracker.h" namespace Core @@ -18,7 +18,7 @@ class System; class PerformanceMetrics { public: - PerformanceMetrics() = default; + PerformanceMetrics(); ~PerformanceMetrics() = default; PerformanceMetrics(const PerformanceMetrics&) = delete; @@ -30,7 +30,6 @@ public: void CountFrame(); void CountVBlank(); - void OnEmulationStateChanged(Core::State state); // Call from CPU thread. void CountThrottleSleep(DT sleep); @@ -69,6 +68,8 @@ private: std::deque m_samples; DT m_time_sleeping{}; + + Common::EventHook m_state_change_hook; }; extern PerformanceMetrics g_perf_metrics;