From 86f17511fce3708aa18267d5588961dc88bddf87 Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Wed, 23 Nov 2022 21:35:21 +0100 Subject: [PATCH] CoreTiming: Move the 'Globals' instance into Core::System. --- Source/Core/Core/CoreTiming.cpp | 36 ++++++++++++++----- Source/Core/Core/CoreTiming.h | 1 - .../Core/PowerPC/Interpreter/Interpreter.cpp | 4 ++- .../PowerPC/Jit64/Jit_SystemRegisters.cpp | 4 ++- .../JitArm64/JitArm64_SystemRegisters.cpp | 4 ++- Source/Core/Core/System.cpp | 7 ++++ Source/Core/Core/System.h | 5 +++ Source/UnitTests/Core/CoreTimingTest.cpp | 6 ++-- 8 files changed, 53 insertions(+), 14 deletions(-) diff --git a/Source/Core/Core/CoreTiming.cpp b/Source/Core/Core/CoreTiming.cpp index fe06a3329d..39c0809e37 100644 --- a/Source/Core/Core/CoreTiming.cpp +++ b/Source/Core/Core/CoreTiming.cpp @@ -74,8 +74,6 @@ static u64 s_fake_dec_start_ticks; // Are we in a function that has been called from Advance() static bool s_is_global_timer_sane; -Globals g; - static EventType* s_ev_lost = nullptr; static size_t s_registered_config_callback_id; @@ -94,7 +92,7 @@ static void EmptyTimedCallback(Core::System& system, u64 userdata, s64 cyclesLat // // Technically it might be more accurate to call this changing the IPC instead of the CPU speed, // but the effect is largely the same. -static int DowncountToCycles(int downcount) +static int DowncountToCycles(CoreTiming::Globals& g, int downcount) { return static_cast(downcount * g.last_OC_factor_inverted); } @@ -127,6 +125,8 @@ void UnregisterAllEvents() void Init() { + auto& g = Core::System::GetInstance().GetCoreTimingGlobals(); + s_registered_config_callback_id = Config::AddConfigChangedCallback([]() { Core::RunAsCPUThread([]() { RefreshConfig(); }); }); RefreshConfig(); @@ -167,6 +167,8 @@ void RefreshConfig() void DoState(PointerWrap& p) { + auto& g = Core::System::GetInstance().GetCoreTimingGlobals(); + std::lock_guard lk(s_ts_write_lock); p.Do(g.slice_length); p.Do(g.global_timer); @@ -226,10 +228,12 @@ void DoState(PointerWrap& p) // it from any other thread, you are doing something evil u64 GetTicks() { + auto& g = Core::System::GetInstance().GetCoreTimingGlobals(); + u64 ticks = static_cast(g.global_timer); if (!s_is_global_timer_sane) { - int downcount = DowncountToCycles(PowerPC::ppcState.downcount); + int downcount = DowncountToCycles(g, PowerPC::ppcState.downcount); ticks += g.slice_length - downcount; } return ticks; @@ -249,6 +253,8 @@ void ScheduleEvent(s64 cycles_into_future, EventType* event_type, u64 userdata, { ASSERT_MSG(POWERPC, event_type, "Event type is nullptr, will crash now."); + auto& g = Core::System::GetInstance().GetCoreTimingGlobals(); + bool from_cpu_thread; if (from == FromThread::ANY) { @@ -309,12 +315,14 @@ void RemoveAllEvents(EventType* event_type) void ForceExceptionCheck(s64 cycles) { + auto& g = Core::System::GetInstance().GetCoreTimingGlobals(); + cycles = std::max(0, cycles); - if (DowncountToCycles(PowerPC::ppcState.downcount) > cycles) + if (DowncountToCycles(g, PowerPC::ppcState.downcount) > cycles) { // downcount is always (much) smaller than MAX_INT so we can safely cast cycles to an int here. // Account for cycles already executed by adjusting the g.slice_length - g.slice_length -= DowncountToCycles(PowerPC::ppcState.downcount) - static_cast(cycles); + g.slice_length -= DowncountToCycles(g, PowerPC::ppcState.downcount) - static_cast(cycles); PowerPC::ppcState.downcount = CyclesToDowncount(static_cast(cycles)); } } @@ -331,9 +339,11 @@ void MoveEvents() void Advance() { + auto& g = Core::System::GetInstance().GetCoreTimingGlobals(); + MoveEvents(); - int cyclesExecuted = g.slice_length - DowncountToCycles(PowerPC::ppcState.downcount); + int cyclesExecuted = g.slice_length - DowncountToCycles(g, PowerPC::ppcState.downcount); g.global_timer += cyclesExecuted; s_last_OC_factor = s_config_OC_factor; g.last_OC_factor_inverted = s_config_OC_inv_factor; @@ -369,6 +379,8 @@ void Advance() void LogPendingEvents() { + auto& g = Core::System::GetInstance().GetCoreTimingGlobals(); + auto clone = s_event_queue; std::sort(clone.begin(), clone.end()); for (const Event& ev : clone) @@ -381,6 +393,8 @@ void LogPendingEvents() // Should only be called from the CPU thread after the PPC clock has changed void AdjustEventQueueTimes(u32 new_ppc_clock, u32 old_ppc_clock) { + auto& g = Core::System::GetInstance().GetCoreTimingGlobals(); + for (Event& ev : s_event_queue) { const s64 ticks = (ev.time - g.global_timer) * new_ppc_clock / old_ppc_clock; @@ -390,6 +404,8 @@ void AdjustEventQueueTimes(u32 new_ppc_clock, u32 old_ppc_clock) void Idle() { + auto& g = Core::System::GetInstance().GetCoreTimingGlobals(); + if (s_config_sync_on_skip_idle) { // When the FIFO is processing data we must not advance because in this way @@ -399,7 +415,7 @@ void Idle() } PowerPC::UpdatePerformanceMonitor(PowerPC::ppcState.downcount, 0, 0); - s_idled_cycles += DowncountToCycles(PowerPC::ppcState.downcount); + s_idled_cycles += DowncountToCycles(g, PowerPC::ppcState.downcount); PowerPC::ppcState.downcount = 0; } @@ -439,21 +455,25 @@ void SetFakeDecStartTicks(u64 val) u64 GetFakeTBStartValue() { + auto& g = Core::System::GetInstance().GetCoreTimingGlobals(); return g.fake_TB_start_value; } void SetFakeTBStartValue(u64 val) { + auto& g = Core::System::GetInstance().GetCoreTimingGlobals(); g.fake_TB_start_value = val; } u64 GetFakeTBStartTicks() { + auto& g = Core::System::GetInstance().GetCoreTimingGlobals(); return g.fake_TB_start_ticks; } void SetFakeTBStartTicks(u64 val) { + auto& g = Core::System::GetInstance().GetCoreTimingGlobals(); g.fake_TB_start_ticks = val; } diff --git a/Source/Core/Core/CoreTiming.h b/Source/Core/Core/CoreTiming.h index 64a5e81a74..55aef4bc72 100644 --- a/Source/Core/Core/CoreTiming.h +++ b/Source/Core/Core/CoreTiming.h @@ -37,7 +37,6 @@ struct Globals u64 fake_TB_start_ticks; float last_OC_factor_inverted; }; -extern Globals g; // CoreTiming begins at the boundary of timing slice -1. An initial call to Advance() is // required to end slice -1 and start slice 0 before the first cycle of code is executed. diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp index 597a07c9c0..ec3d0229b9 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp @@ -212,13 +212,15 @@ int Interpreter::SingleStepInner() void Interpreter::SingleStep() { + auto& core_timing_globals = Core::System::GetInstance().GetCoreTimingGlobals(); + // Declare start of new slice CoreTiming::Advance(); SingleStepInner(); // The interpreter ignores instruction timing information outside the 'fast runloop'. - CoreTiming::g.slice_length = 1; + core_timing_globals.slice_length = 1; PowerPC::ppcState.downcount = 0; if (PowerPC::ppcState.Exceptions != 0) diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp index f611fd7ee1..eb2e938648 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp @@ -14,6 +14,7 @@ #include "Core/PowerPC/Jit64/RegCache/JitRegCache.h" #include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h" #include "Core/PowerPC/PowerPC.h" +#include "Core/System.h" using namespace Gen; @@ -322,7 +323,8 @@ void Jit64::mfspr(UGeckoInstruction inst) RCX64Reg rax = gpr.Scratch(RAX); RCX64Reg rcx = gpr.Scratch(RCX); - MOV(64, rcx, ImmPtr(&CoreTiming::g)); + auto& core_timing_globals = Core::System::GetInstance().GetCoreTimingGlobals(); + MOV(64, rcx, ImmPtr(&core_timing_globals)); // An inline implementation of CoreTiming::GetFakeTimeBase, since in timer-heavy games the // cost of calling out to C for this is actually significant. diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp index 6a8245b8bb..d93700e742 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp @@ -13,6 +13,7 @@ #include "Core/PowerPC/Interpreter/ExceptionUtils.h" #include "Core/PowerPC/PPCTables.h" #include "Core/PowerPC/PowerPC.h" +#include "Core/System.h" using namespace Arm64Gen; @@ -306,7 +307,8 @@ void JitArm64::mfspr(UGeckoInstruction inst) // An inline implementation of CoreTiming::GetFakeTimeBase, since in timer-heavy games the // cost of calling out to C for this is actually significant. - MOVP2R(Xg, &CoreTiming::g); + auto& core_timing_globals = Core::System::GetInstance().GetCoreTimingGlobals(); + MOVP2R(Xg, &core_timing_globals); LDR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(downcount)); m_float_emit.SCVTF(SC, WA); diff --git a/Source/Core/Core/System.cpp b/Source/Core/Core/System.cpp index 62d119f071..552c4c4196 100644 --- a/Source/Core/Core/System.cpp +++ b/Source/Core/Core/System.cpp @@ -7,6 +7,7 @@ #include "AudioCommon/SoundStream.h" #include "Core/Config/MainSettings.h" +#include "Core/CoreTiming.h" #include "Core/HW/AudioInterface.h" #include "Core/HW/DSP.h" #include "Core/HW/DVD/DVDInterface.h" @@ -26,6 +27,7 @@ struct System::Impl bool m_audio_dump_started = false; AudioInterface::AudioInterfaceState m_audio_interface_state; + CoreTiming::Globals m_core_timing_globals; DSP::DSPState m_dsp_state; DVDInterface::DVDInterfaceState m_dvd_interface_state; DVDThread::DVDThreadState m_dvd_thread_state; @@ -84,6 +86,11 @@ AudioInterface::AudioInterfaceState& System::GetAudioInterfaceState() const return m_impl->m_audio_interface_state; } +CoreTiming::Globals& System::GetCoreTimingGlobals() const +{ + return m_impl->m_core_timing_globals; +} + DSP::DSPState& System::GetDSPState() const { return m_impl->m_dsp_state; diff --git a/Source/Core/Core/System.h b/Source/Core/Core/System.h index 3e70f215e4..b2ad82d12d 100644 --- a/Source/Core/Core/System.h +++ b/Source/Core/Core/System.h @@ -12,6 +12,10 @@ namespace AudioInterface { class AudioInterfaceState; }; +namespace CoreTiming +{ +struct Globals; +} namespace DSP { class DSPState; @@ -76,6 +80,7 @@ public: void SetAudioDumpStarted(bool started); AudioInterface::AudioInterfaceState& GetAudioInterfaceState() const; + CoreTiming::Globals& GetCoreTimingGlobals() const; DSP::DSPState& GetDSPState() const; DVDInterface::DVDInterfaceState& GetDVDInterfaceState() const; DVDThread::DVDThreadState& GetDVDThreadState() const; diff --git a/Source/UnitTests/Core/CoreTimingTest.cpp b/Source/UnitTests/Core/CoreTimingTest.cpp index b8ca8cc01b..83bb06097e 100644 --- a/Source/UnitTests/Core/CoreTimingTest.cpp +++ b/Source/UnitTests/Core/CoreTimingTest.cpp @@ -14,6 +14,7 @@ #include "Core/Core.h" #include "Core/CoreTiming.h" #include "Core/PowerPC/PowerPC.h" +#include "Core/System.h" #include "UICommon/UICommon.h" // Numbers are chosen randomly to make sure the correct one is given. @@ -279,9 +280,10 @@ TEST(CoreTiming, ScheduleIntoPast) // the stale value, i.e. effectively half-way through the previous slice. // NOTE: We're only testing that the scheduler doesn't break, not whether this makes sense. Core::UndeclareAsCPUThread(); - CoreTiming::g.global_timer -= 1000; + auto& core_timing_globals = Core::System::GetInstance().GetCoreTimingGlobals(); + core_timing_globals.global_timer -= 1000; CoreTiming::ScheduleEvent(0, cb_b, CB_IDS[1], CoreTiming::FromThread::NON_CPU); - CoreTiming::g.global_timer += 1000; + core_timing_globals.global_timer += 1000; Core::DeclareAsCPUThread(); AdvanceAndCheck(1, MAX_SLICE_LENGTH, MAX_SLICE_LENGTH + 1000);