summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Lioncash2019-02-14 12:42:58 -0500
committerGravatar Lioncash2019-02-15 21:50:25 -0500
commitbd983414f643b734a1f8bebe3183723733344f72 (patch)
treebda0421458439e25cba9d772a6a79b56e473d72e
parentMerge pull request #2113 from ReinUsesLisp/vulkan-base (diff)
downloadyuzu-bd983414f643b734a1f8bebe3183723733344f72.tar.gz
yuzu-bd983414f643b734a1f8bebe3183723733344f72.tar.xz
yuzu-bd983414f643b734a1f8bebe3183723733344f72.zip
core_timing: Convert core timing into a class
Gets rid of the largest set of mutable global state within the core. This also paves a way for eliminating usages of GetInstance() on the System class as a follow-up. Note that no behavioral changes have been made, and this simply extracts the functionality into a class. This also has the benefit of making dependencies on the core timing functionality explicit within the relevant interfaces.
-rw-r--r--src/audio_core/audio_out.cpp5
-rw-r--r--src/audio_core/audio_out.h8
-rw-r--r--src/audio_core/audio_renderer.cpp7
-rw-r--r--src/audio_core/audio_renderer.h6
-rw-r--r--src/audio_core/stream.cpp11
-rw-r--r--src/audio_core/stream.h8
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp12
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.h8
-rw-r--r--src/core/arm/unicorn/arm_unicorn.cpp6
-rw-r--r--src/core/arm/unicorn/arm_unicorn.h8
-rw-r--r--src/core/core.cpp19
-rw-r--r--src/core/core.h10
-rw-r--r--src/core/core_cpu.cpp15
-rw-r--r--src/core/core_cpu.h8
-rw-r--r--src/core/core_timing.cpp189
-rw-r--r--src/core/core_timing.h211
-rw-r--r--src/core/cpu_core_manager.cpp3
-rw-r--r--src/core/hle/kernel/kernel.cpp12
-rw-r--r--src/core/hle/kernel/kernel.h9
-rw-r--r--src/core/hle/kernel/scheduler.cpp2
-rw-r--r--src/core/hle/kernel/svc.cpp10
-rw-r--r--src/core/hle/kernel/thread.cpp19
-rw-r--r--src/core/hle/service/audio/audout_u.cpp10
-rw-r--r--src/core/hle/service/audio/audren_u.cpp9
-rw-r--r--src/core/hle/service/hid/controllers/controller_base.h7
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.cpp5
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.h2
-rw-r--r--src/core/hle/service/hid/controllers/gesture.cpp5
-rw-r--r--src/core/hle/service/hid/controllers/gesture.h2
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.cpp5
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.h2
-rw-r--r--src/core/hle/service/hid/controllers/mouse.cpp5
-rw-r--r--src/core/hle/service/hid/controllers/mouse.h2
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp5
-rw-r--r--src/core/hle/service/hid/controllers/npad.h2
-rw-r--r--src/core/hle/service/hid/controllers/stubbed.cpp5
-rw-r--r--src/core/hle/service/hid/controllers/stubbed.h2
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.cpp7
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.h2
-rw-r--r--src/core/hle/service/hid/controllers/xpad.cpp5
-rw-r--r--src/core/hle/service/hid/controllers/xpad.h2
-rw-r--r--src/core/hle/service/hid/hid.cpp18
-rw-r--r--src/core/hle/service/hid/irs.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp3
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp10
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h8
-rw-r--r--src/core/hle/service/service.cpp5
-rw-r--r--src/core/hle/service/service.h15
-rw-r--r--src/core/hle/service/time/time.cpp7
-rw-r--r--src/tests/core/core_timing.cpp215
-rw-r--r--src/video_core/engines/maxwell_3d.cpp2
-rw-r--r--src/video_core/gpu.cpp3
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp2
53 files changed, 548 insertions, 412 deletions
diff --git a/src/audio_core/audio_out.cpp b/src/audio_core/audio_out.cpp
index 50d2a1ed3..8619a3f03 100644
--- a/src/audio_core/audio_out.cpp
+++ b/src/audio_core/audio_out.cpp
@@ -26,14 +26,15 @@ static Stream::Format ChannelsToStreamFormat(u32 num_channels) {
26 return {}; 26 return {};
27} 27}
28 28
29StreamPtr AudioOut::OpenStream(u32 sample_rate, u32 num_channels, std::string&& name, 29StreamPtr AudioOut::OpenStream(Core::Timing::CoreTiming& core_timing, u32 sample_rate,
30 u32 num_channels, std::string&& name,
30 Stream::ReleaseCallback&& release_callback) { 31 Stream::ReleaseCallback&& release_callback) {
31 if (!sink) { 32 if (!sink) {
32 sink = CreateSinkFromID(Settings::values.sink_id, Settings::values.audio_device_id); 33 sink = CreateSinkFromID(Settings::values.sink_id, Settings::values.audio_device_id);
33 } 34 }
34 35
35 return std::make_shared<Stream>( 36 return std::make_shared<Stream>(
36 sample_rate, ChannelsToStreamFormat(num_channels), std::move(release_callback), 37 core_timing, sample_rate, ChannelsToStreamFormat(num_channels), std::move(release_callback),
37 sink->AcquireSinkStream(sample_rate, num_channels, name), std::move(name)); 38 sink->AcquireSinkStream(sample_rate, num_channels, name), std::move(name));
38} 39}
39 40
diff --git a/src/audio_core/audio_out.h b/src/audio_core/audio_out.h
index df9607ac7..b07588287 100644
--- a/src/audio_core/audio_out.h
+++ b/src/audio_core/audio_out.h
@@ -13,6 +13,10 @@
13#include "audio_core/stream.h" 13#include "audio_core/stream.h"
14#include "common/common_types.h" 14#include "common/common_types.h"
15 15
16namespace Core::Timing {
17class CoreTiming;
18}
19
16namespace AudioCore { 20namespace AudioCore {
17 21
18/** 22/**
@@ -21,8 +25,8 @@ namespace AudioCore {
21class AudioOut { 25class AudioOut {
22public: 26public:
23 /// Opens a new audio stream 27 /// Opens a new audio stream
24 StreamPtr OpenStream(u32 sample_rate, u32 num_channels, std::string&& name, 28 StreamPtr OpenStream(Core::Timing::CoreTiming& core_timing, u32 sample_rate, u32 num_channels,
25 Stream::ReleaseCallback&& release_callback); 29 std::string&& name, Stream::ReleaseCallback&& release_callback);
26 30
27 /// Returns a vector of recently released buffers specified by tag for the specified stream 31 /// Returns a vector of recently released buffers specified by tag for the specified stream
28 std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(StreamPtr stream, std::size_t max_count); 32 std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(StreamPtr stream, std::size_t max_count);
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp
index 00c026511..9a0939883 100644
--- a/src/audio_core/audio_renderer.cpp
+++ b/src/audio_core/audio_renderer.cpp
@@ -8,6 +8,7 @@
8#include "audio_core/codec.h" 8#include "audio_core/codec.h"
9#include "common/assert.h" 9#include "common/assert.h"
10#include "common/logging/log.h" 10#include "common/logging/log.h"
11#include "core/core.h"
11#include "core/hle/kernel/writable_event.h" 12#include "core/hle/kernel/writable_event.h"
12#include "core/memory.h" 13#include "core/memory.h"
13 14
@@ -71,14 +72,14 @@ private:
71 EffectOutStatus out_status{}; 72 EffectOutStatus out_status{};
72 EffectInStatus info{}; 73 EffectInStatus info{};
73}; 74};
74AudioRenderer::AudioRenderer(AudioRendererParameter params, 75AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, AudioRendererParameter params,
75 Kernel::SharedPtr<Kernel::WritableEvent> buffer_event) 76 Kernel::SharedPtr<Kernel::WritableEvent> buffer_event)
76 : worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count), 77 : worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count),
77 effects(params.effect_count) { 78 effects(params.effect_count) {
78 79
79 audio_out = std::make_unique<AudioCore::AudioOut>(); 80 audio_out = std::make_unique<AudioCore::AudioOut>();
80 stream = audio_out->OpenStream(STREAM_SAMPLE_RATE, STREAM_NUM_CHANNELS, "AudioRenderer", 81 stream = audio_out->OpenStream(core_timing, STREAM_SAMPLE_RATE, STREAM_NUM_CHANNELS,
81 [=]() { buffer_event->Signal(); }); 82 "AudioRenderer", [=]() { buffer_event->Signal(); });
82 audio_out->StartStream(stream); 83 audio_out->StartStream(stream);
83 84
84 QueueMixedBuffer(0); 85 QueueMixedBuffer(0);
diff --git a/src/audio_core/audio_renderer.h b/src/audio_core/audio_renderer.h
index 7826881bf..201ec7a3c 100644
--- a/src/audio_core/audio_renderer.h
+++ b/src/audio_core/audio_renderer.h
@@ -14,6 +14,10 @@
14#include "common/swap.h" 14#include "common/swap.h"
15#include "core/hle/kernel/object.h" 15#include "core/hle/kernel/object.h"
16 16
17namespace Core::Timing {
18class CoreTiming;
19}
20
17namespace Kernel { 21namespace Kernel {
18class WritableEvent; 22class WritableEvent;
19} 23}
@@ -208,7 +212,7 @@ static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has wrong size
208 212
209class AudioRenderer { 213class AudioRenderer {
210public: 214public:
211 AudioRenderer(AudioRendererParameter params, 215 AudioRenderer(Core::Timing::CoreTiming& core_timing, AudioRendererParameter params,
212 Kernel::SharedPtr<Kernel::WritableEvent> buffer_event); 216 Kernel::SharedPtr<Kernel::WritableEvent> buffer_event);
213 ~AudioRenderer(); 217 ~AudioRenderer();
214 218
diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp
index 8ab5649df..d89ff30b7 100644
--- a/src/audio_core/stream.cpp
+++ b/src/audio_core/stream.cpp
@@ -32,12 +32,12 @@ u32 Stream::GetNumChannels() const {
32 return {}; 32 return {};
33} 33}
34 34
35Stream::Stream(u32 sample_rate, Format format, ReleaseCallback&& release_callback, 35Stream::Stream(Core::Timing::CoreTiming& core_timing, u32 sample_rate, Format format,
36 SinkStream& sink_stream, std::string&& name_) 36 ReleaseCallback&& release_callback, SinkStream& sink_stream, std::string&& name_)
37 : sample_rate{sample_rate}, format{format}, release_callback{std::move(release_callback)}, 37 : sample_rate{sample_rate}, format{format}, release_callback{std::move(release_callback)},
38 sink_stream{sink_stream}, name{std::move(name_)} { 38 sink_stream{sink_stream}, core_timing{core_timing}, name{std::move(name_)} {
39 39
40 release_event = Core::Timing::RegisterEvent( 40 release_event = core_timing.RegisterEvent(
41 name, [this](u64 userdata, int cycles_late) { ReleaseActiveBuffer(); }); 41 name, [this](u64 userdata, int cycles_late) { ReleaseActiveBuffer(); });
42} 42}
43 43
@@ -99,8 +99,7 @@ void Stream::PlayNextBuffer() {
99 99
100 sink_stream.EnqueueSamples(GetNumChannels(), active_buffer->GetSamples()); 100 sink_stream.EnqueueSamples(GetNumChannels(), active_buffer->GetSamples());
101 101
102 Core::Timing::ScheduleEventThreadsafe(GetBufferReleaseCycles(*active_buffer), release_event, 102 core_timing.ScheduleEventThreadsafe(GetBufferReleaseCycles(*active_buffer), release_event, {});
103 {});
104} 103}
105 104
106void Stream::ReleaseActiveBuffer() { 105void Stream::ReleaseActiveBuffer() {
diff --git a/src/audio_core/stream.h b/src/audio_core/stream.h
index caa775544..05071243b 100644
--- a/src/audio_core/stream.h
+++ b/src/audio_core/stream.h
@@ -14,8 +14,9 @@
14#include "common/common_types.h" 14#include "common/common_types.h"
15 15
16namespace Core::Timing { 16namespace Core::Timing {
17class CoreTiming;
17struct EventType; 18struct EventType;
18} 19} // namespace Core::Timing
19 20
20namespace AudioCore { 21namespace AudioCore {
21 22
@@ -42,8 +43,8 @@ public:
42 /// Callback function type, used to change guest state on a buffer being released 43 /// Callback function type, used to change guest state on a buffer being released
43 using ReleaseCallback = std::function<void()>; 44 using ReleaseCallback = std::function<void()>;
44 45
45 Stream(u32 sample_rate, Format format, ReleaseCallback&& release_callback, 46 Stream(Core::Timing::CoreTiming& core_timing, u32 sample_rate, Format format,
46 SinkStream& sink_stream, std::string&& name_); 47 ReleaseCallback&& release_callback, SinkStream& sink_stream, std::string&& name_);
47 48
48 /// Plays the audio stream 49 /// Plays the audio stream
49 void Play(); 50 void Play();
@@ -100,6 +101,7 @@ private:
100 std::queue<BufferPtr> queued_buffers; ///< Buffers queued to be played in the stream 101 std::queue<BufferPtr> queued_buffers; ///< Buffers queued to be played in the stream
101 std::queue<BufferPtr> released_buffers; ///< Buffers recently released from the stream 102 std::queue<BufferPtr> released_buffers; ///< Buffers recently released from the stream
102 SinkStream& sink_stream; ///< Output sink for the stream 103 SinkStream& sink_stream; ///< Output sink for the stream
104 Core::Timing::CoreTiming& core_timing; ///< Core timing instance.
103 std::string name; ///< Name of the stream, must be unique 105 std::string name; ///< Name of the stream, must be unique
104}; 106};
105 107
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index f28951f8a..9b7ca4030 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -112,14 +112,14 @@ public:
112 // Always execute at least one tick. 112 // Always execute at least one tick.
113 amortized_ticks = std::max<u64>(amortized_ticks, 1); 113 amortized_ticks = std::max<u64>(amortized_ticks, 1);
114 114
115 Timing::AddTicks(amortized_ticks); 115 parent.core_timing.AddTicks(amortized_ticks);
116 num_interpreted_instructions = 0; 116 num_interpreted_instructions = 0;
117 } 117 }
118 u64 GetTicksRemaining() override { 118 u64 GetTicksRemaining() override {
119 return std::max(Timing::GetDowncount(), 0); 119 return std::max(parent.core_timing.GetDowncount(), 0);
120 } 120 }
121 u64 GetCNTPCT() override { 121 u64 GetCNTPCT() override {
122 return Timing::GetTicks(); 122 return parent.core_timing.GetTicks();
123 } 123 }
124 124
125 ARM_Dynarmic& parent; 125 ARM_Dynarmic& parent;
@@ -172,8 +172,10 @@ void ARM_Dynarmic::Step() {
172 cb->InterpreterFallback(jit->GetPC(), 1); 172 cb->InterpreterFallback(jit->GetPC(), 1);
173} 173}
174 174
175ARM_Dynarmic::ARM_Dynarmic(ExclusiveMonitor& exclusive_monitor, std::size_t core_index) 175ARM_Dynarmic::ARM_Dynarmic(Timing::CoreTiming& core_timing, ExclusiveMonitor& exclusive_monitor,
176 : cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), core_index{core_index}, 176 std::size_t core_index)
177 : cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), inner_unicorn{core_timing},
178 core_index{core_index}, core_timing{core_timing},
177 exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} { 179 exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {
178 ThreadContext ctx{}; 180 ThreadContext ctx{};
179 inner_unicorn.SaveContext(ctx); 181 inner_unicorn.SaveContext(ctx);
diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h
index 512bf8ce9..6cc458296 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.h
+++ b/src/core/arm/dynarmic/arm_dynarmic.h
@@ -16,6 +16,10 @@ namespace Memory {
16struct PageTable; 16struct PageTable;
17} 17}
18 18
19namespace Core::Timing {
20class CoreTiming;
21}
22
19namespace Core { 23namespace Core {
20 24
21class ARM_Dynarmic_Callbacks; 25class ARM_Dynarmic_Callbacks;
@@ -23,7 +27,8 @@ class DynarmicExclusiveMonitor;
23 27
24class ARM_Dynarmic final : public ARM_Interface { 28class ARM_Dynarmic final : public ARM_Interface {
25public: 29public:
26 ARM_Dynarmic(ExclusiveMonitor& exclusive_monitor, std::size_t core_index); 30 ARM_Dynarmic(Timing::CoreTiming& core_timing, ExclusiveMonitor& exclusive_monitor,
31 std::size_t core_index);
27 ~ARM_Dynarmic(); 32 ~ARM_Dynarmic();
28 33
29 void MapBackingMemory(VAddr address, std::size_t size, u8* memory, 34 void MapBackingMemory(VAddr address, std::size_t size, u8* memory,
@@ -62,6 +67,7 @@ private:
62 ARM_Unicorn inner_unicorn; 67 ARM_Unicorn inner_unicorn;
63 68
64 std::size_t core_index; 69 std::size_t core_index;
70 Timing::CoreTiming& core_timing;
65 DynarmicExclusiveMonitor& exclusive_monitor; 71 DynarmicExclusiveMonitor& exclusive_monitor;
66 72
67 Memory::PageTable* current_page_table = nullptr; 73 Memory::PageTable* current_page_table = nullptr;
diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp
index c36c15c02..a542a098b 100644
--- a/src/core/arm/unicorn/arm_unicorn.cpp
+++ b/src/core/arm/unicorn/arm_unicorn.cpp
@@ -72,7 +72,7 @@ static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int si
72 return {}; 72 return {};
73} 73}
74 74
75ARM_Unicorn::ARM_Unicorn() { 75ARM_Unicorn::ARM_Unicorn(Timing::CoreTiming& core_timing) : core_timing{core_timing} {
76 CHECKED(uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc)); 76 CHECKED(uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc));
77 77
78 auto fpv = 3 << 20; 78 auto fpv = 3 << 20;
@@ -177,7 +177,7 @@ void ARM_Unicorn::Run() {
177 if (GDBStub::IsServerEnabled()) { 177 if (GDBStub::IsServerEnabled()) {
178 ExecuteInstructions(std::max(4000000, 0)); 178 ExecuteInstructions(std::max(4000000, 0));
179 } else { 179 } else {
180 ExecuteInstructions(std::max(Timing::GetDowncount(), 0)); 180 ExecuteInstructions(std::max(core_timing.GetDowncount(), 0));
181 } 181 }
182} 182}
183 183
@@ -190,7 +190,7 @@ MICROPROFILE_DEFINE(ARM_Jit_Unicorn, "ARM JIT", "Unicorn", MP_RGB(255, 64, 64));
190void ARM_Unicorn::ExecuteInstructions(int num_instructions) { 190void ARM_Unicorn::ExecuteInstructions(int num_instructions) {
191 MICROPROFILE_SCOPE(ARM_Jit_Unicorn); 191 MICROPROFILE_SCOPE(ARM_Jit_Unicorn);
192 CHECKED(uc_emu_start(uc, GetPC(), 1ULL << 63, 0, num_instructions)); 192 CHECKED(uc_emu_start(uc, GetPC(), 1ULL << 63, 0, num_instructions));
193 Timing::AddTicks(num_instructions); 193 core_timing.AddTicks(num_instructions);
194 if (GDBStub::IsServerEnabled()) { 194 if (GDBStub::IsServerEnabled()) {
195 if (last_bkpt_hit) { 195 if (last_bkpt_hit) {
196 uc_reg_write(uc, UC_ARM64_REG_PC, &last_bkpt.address); 196 uc_reg_write(uc, UC_ARM64_REG_PC, &last_bkpt.address);
diff --git a/src/core/arm/unicorn/arm_unicorn.h b/src/core/arm/unicorn/arm_unicorn.h
index 75761950b..dbd6955ea 100644
--- a/src/core/arm/unicorn/arm_unicorn.h
+++ b/src/core/arm/unicorn/arm_unicorn.h
@@ -9,12 +9,17 @@
9#include "core/arm/arm_interface.h" 9#include "core/arm/arm_interface.h"
10#include "core/gdbstub/gdbstub.h" 10#include "core/gdbstub/gdbstub.h"
11 11
12namespace Core::Timing {
13class CoreTiming;
14}
15
12namespace Core { 16namespace Core {
13 17
14class ARM_Unicorn final : public ARM_Interface { 18class ARM_Unicorn final : public ARM_Interface {
15public: 19public:
16 ARM_Unicorn(); 20 explicit ARM_Unicorn(Timing::CoreTiming& core_timing);
17 ~ARM_Unicorn(); 21 ~ARM_Unicorn();
22
18 void MapBackingMemory(VAddr address, std::size_t size, u8* memory, 23 void MapBackingMemory(VAddr address, std::size_t size, u8* memory,
19 Kernel::VMAPermission perms) override; 24 Kernel::VMAPermission perms) override;
20 void UnmapMemory(VAddr address, std::size_t size) override; 25 void UnmapMemory(VAddr address, std::size_t size) override;
@@ -43,6 +48,7 @@ public:
43 48
44private: 49private:
45 uc_engine* uc{}; 50 uc_engine* uc{};
51 Timing::CoreTiming& core_timing;
46 GDBStub::BreakpointAddress last_bkpt{}; 52 GDBStub::BreakpointAddress last_bkpt{};
47 bool last_bkpt_hit; 53 bool last_bkpt_hit;
48}; 54};
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 4d9d21ee4..8aa0932c5 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -94,8 +94,8 @@ struct System::Impl {
94 ResultStatus Init(System& system, Frontend::EmuWindow& emu_window) { 94 ResultStatus Init(System& system, Frontend::EmuWindow& emu_window) {
95 LOG_DEBUG(HW_Memory, "initialized OK"); 95 LOG_DEBUG(HW_Memory, "initialized OK");
96 96
97 Timing::Init(); 97 core_timing.Initialize();
98 kernel.Initialize(); 98 kernel.Initialize(core_timing);
99 99
100 const auto current_time = std::chrono::duration_cast<std::chrono::seconds>( 100 const auto current_time = std::chrono::duration_cast<std::chrono::seconds>(
101 std::chrono::system_clock::now().time_since_epoch()); 101 std::chrono::system_clock::now().time_since_epoch());
@@ -120,7 +120,7 @@ struct System::Impl {
120 telemetry_session = std::make_unique<Core::TelemetrySession>(); 120 telemetry_session = std::make_unique<Core::TelemetrySession>();
121 service_manager = std::make_shared<Service::SM::ServiceManager>(); 121 service_manager = std::make_shared<Service::SM::ServiceManager>();
122 122
123 Service::Init(service_manager, *virtual_filesystem); 123 Service::Init(service_manager, system, *virtual_filesystem);
124 GDBStub::Init(); 124 GDBStub::Init();
125 125
126 renderer = VideoCore::CreateRenderer(emu_window, system); 126 renderer = VideoCore::CreateRenderer(emu_window, system);
@@ -205,7 +205,7 @@ struct System::Impl {
205 205
206 // Shutdown kernel and core timing 206 // Shutdown kernel and core timing
207 kernel.Shutdown(); 207 kernel.Shutdown();
208 Timing::Shutdown(); 208 core_timing.Shutdown();
209 209
210 // Close app loader 210 // Close app loader
211 app_loader.reset(); 211 app_loader.reset();
@@ -232,9 +232,10 @@ struct System::Impl {
232 } 232 }
233 233
234 PerfStatsResults GetAndResetPerfStats() { 234 PerfStatsResults GetAndResetPerfStats() {
235 return perf_stats.GetAndResetStats(Timing::GetGlobalTimeUs()); 235 return perf_stats.GetAndResetStats(core_timing.GetGlobalTimeUs());
236 } 236 }
237 237
238 Timing::CoreTiming core_timing;
238 Kernel::KernelCore kernel; 239 Kernel::KernelCore kernel;
239 /// RealVfsFilesystem instance 240 /// RealVfsFilesystem instance
240 FileSys::VirtualFilesystem virtual_filesystem; 241 FileSys::VirtualFilesystem virtual_filesystem;
@@ -396,6 +397,14 @@ const Kernel::KernelCore& System::Kernel() const {
396 return impl->kernel; 397 return impl->kernel;
397} 398}
398 399
400Timing::CoreTiming& System::CoreTiming() {
401 return impl->core_timing;
402}
403
404const Timing::CoreTiming& System::CoreTiming() const {
405 return impl->core_timing;
406}
407
399Core::PerfStats& System::GetPerfStats() { 408Core::PerfStats& System::GetPerfStats() {
400 return impl->perf_stats; 409 return impl->perf_stats;
401} 410}
diff --git a/src/core/core.h b/src/core/core.h
index 511a5ad3a..d720013f7 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -47,6 +47,10 @@ namespace VideoCore {
47class RendererBase; 47class RendererBase;
48} // namespace VideoCore 48} // namespace VideoCore
49 49
50namespace Core::Timing {
51class CoreTiming;
52}
53
50namespace Core { 54namespace Core {
51 55
52class ARM_Interface; 56class ARM_Interface;
@@ -205,6 +209,12 @@ public:
205 /// Provides a constant pointer to the current process. 209 /// Provides a constant pointer to the current process.
206 const Kernel::Process* CurrentProcess() const; 210 const Kernel::Process* CurrentProcess() const;
207 211
212 /// Provides a reference to the core timing instance.
213 Timing::CoreTiming& CoreTiming();
214
215 /// Provides a constant reference to the core timing instance.
216 const Timing::CoreTiming& CoreTiming() const;
217
208 /// Provides a reference to the kernel instance. 218 /// Provides a reference to the kernel instance.
209 Kernel::KernelCore& Kernel(); 219 Kernel::KernelCore& Kernel();
210 220
diff --git a/src/core/core_cpu.cpp b/src/core/core_cpu.cpp
index 452366250..54aa21a3a 100644
--- a/src/core/core_cpu.cpp
+++ b/src/core/core_cpu.cpp
@@ -49,17 +49,18 @@ bool CpuBarrier::Rendezvous() {
49 return false; 49 return false;
50} 50}
51 51
52Cpu::Cpu(ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_barrier, std::size_t core_index) 52Cpu::Cpu(Timing::CoreTiming& core_timing, ExclusiveMonitor& exclusive_monitor,
53 : cpu_barrier{cpu_barrier}, core_index{core_index} { 53 CpuBarrier& cpu_barrier, std::size_t core_index)
54 : cpu_barrier{cpu_barrier}, core_timing{core_timing}, core_index{core_index} {
54 if (Settings::values.use_cpu_jit) { 55 if (Settings::values.use_cpu_jit) {
55#ifdef ARCHITECTURE_x86_64 56#ifdef ARCHITECTURE_x86_64
56 arm_interface = std::make_unique<ARM_Dynarmic>(exclusive_monitor, core_index); 57 arm_interface = std::make_unique<ARM_Dynarmic>(core_timing, exclusive_monitor, core_index);
57#else 58#else
58 arm_interface = std::make_unique<ARM_Unicorn>(); 59 arm_interface = std::make_unique<ARM_Unicorn>();
59 LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); 60 LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
60#endif 61#endif
61 } else { 62 } else {
62 arm_interface = std::make_unique<ARM_Unicorn>(); 63 arm_interface = std::make_unique<ARM_Unicorn>(core_timing);
63 } 64 }
64 65
65 scheduler = std::make_unique<Kernel::Scheduler>(*arm_interface); 66 scheduler = std::make_unique<Kernel::Scheduler>(*arm_interface);
@@ -93,14 +94,14 @@ void Cpu::RunLoop(bool tight_loop) {
93 94
94 if (IsMainCore()) { 95 if (IsMainCore()) {
95 // TODO(Subv): Only let CoreTiming idle if all 4 cores are idling. 96 // TODO(Subv): Only let CoreTiming idle if all 4 cores are idling.
96 Timing::Idle(); 97 core_timing.Idle();
97 Timing::Advance(); 98 core_timing.Advance();
98 } 99 }
99 100
100 PrepareReschedule(); 101 PrepareReschedule();
101 } else { 102 } else {
102 if (IsMainCore()) { 103 if (IsMainCore()) {
103 Timing::Advance(); 104 core_timing.Advance();
104 } 105 }
105 106
106 if (tight_loop) { 107 if (tight_loop) {
diff --git a/src/core/core_cpu.h b/src/core/core_cpu.h
index 1d2bdc6cd..e2204c6b0 100644
--- a/src/core/core_cpu.h
+++ b/src/core/core_cpu.h
@@ -15,6 +15,10 @@ namespace Kernel {
15class Scheduler; 15class Scheduler;
16} 16}
17 17
18namespace Core::Timing {
19class CoreTiming;
20}
21
18namespace Core { 22namespace Core {
19 23
20class ARM_Interface; 24class ARM_Interface;
@@ -41,7 +45,8 @@ private:
41 45
42class Cpu { 46class Cpu {
43public: 47public:
44 Cpu(ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_barrier, std::size_t core_index); 48 Cpu(Timing::CoreTiming& core_timing, ExclusiveMonitor& exclusive_monitor,
49 CpuBarrier& cpu_barrier, std::size_t core_index);
45 ~Cpu(); 50 ~Cpu();
46 51
47 void RunLoop(bool tight_loop = true); 52 void RunLoop(bool tight_loop = true);
@@ -82,6 +87,7 @@ private:
82 std::unique_ptr<ARM_Interface> arm_interface; 87 std::unique_ptr<ARM_Interface> arm_interface;
83 CpuBarrier& cpu_barrier; 88 CpuBarrier& cpu_barrier;
84 std::unique_ptr<Kernel::Scheduler> scheduler; 89 std::unique_ptr<Kernel::Scheduler> scheduler;
90 Timing::CoreTiming& core_timing;
85 91
86 std::atomic<bool> reschedule_pending = false; 92 std::atomic<bool> reschedule_pending = false;
87 std::size_t core_index; 93 std::size_t core_index;
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index 4ea00c277..a0dd5db24 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -8,94 +8,42 @@
8#include <mutex> 8#include <mutex>
9#include <string> 9#include <string>
10#include <tuple> 10#include <tuple>
11#include <unordered_map> 11
12#include <vector>
13#include "common/assert.h" 12#include "common/assert.h"
14#include "common/thread.h" 13#include "common/thread.h"
15#include "common/threadsafe_queue.h"
16#include "core/core_timing_util.h" 14#include "core/core_timing_util.h"
17 15
18namespace Core::Timing { 16namespace Core::Timing {
19 17
20static s64 global_timer; 18constexpr int MAX_SLICE_LENGTH = 20000;
21static int slice_length;
22static int downcount;
23
24struct EventType {
25 TimedCallback callback;
26 const std::string* name;
27};
28 19
29struct Event { 20struct CoreTiming::Event {
30 s64 time; 21 s64 time;
31 u64 fifo_order; 22 u64 fifo_order;
32 u64 userdata; 23 u64 userdata;
33 const EventType* type; 24 const EventType* type;
34};
35
36// Sort by time, unless the times are the same, in which case sort by the order added to the queue
37static bool operator>(const Event& left, const Event& right) {
38 return std::tie(left.time, left.fifo_order) > std::tie(right.time, right.fifo_order);
39}
40
41static bool operator<(const Event& left, const Event& right) {
42 return std::tie(left.time, left.fifo_order) < std::tie(right.time, right.fifo_order);
43}
44
45// unordered_map stores each element separately as a linked list node so pointers to elements
46// remain stable regardless of rehashes/resizing.
47static std::unordered_map<std::string, EventType> event_types;
48 25
49// The queue is a min-heap using std::make_heap/push_heap/pop_heap. 26 // Sort by time, unless the times are the same, in which case sort by
50// We don't use std::priority_queue because we need to be able to serialize, unserialize and 27 // the order added to the queue
51// erase arbitrary events (RemoveEvent()) regardless of the queue order. These aren't accomodated 28 friend bool operator>(const Event& left, const Event& right) {
52// by the standard adaptor class. 29 return std::tie(left.time, left.fifo_order) > std::tie(right.time, right.fifo_order);
53static std::vector<Event> event_queue; 30 }
54static u64 event_fifo_id;
55// the queue for storing the events from other threads threadsafe until they will be added
56// to the event_queue by the emu thread
57static Common::MPSCQueue<Event> ts_queue;
58
59// the queue for unscheduling the events from other threads threadsafe
60static Common::MPSCQueue<std::pair<const EventType*, u64>> unschedule_queue;
61
62constexpr int MAX_SLICE_LENGTH = 20000;
63
64static s64 idled_cycles;
65
66// Are we in a function that has been called from Advance()
67// If events are sheduled from a function that gets called from Advance(),
68// don't change slice_length and downcount.
69static bool is_global_timer_sane;
70
71static EventType* ev_lost = nullptr;
72
73EventType* RegisterEvent(const std::string& name, TimedCallback callback) {
74 // check for existing type with same name.
75 // we want event type names to remain unique so that we can use them for serialization.
76 ASSERT_MSG(event_types.find(name) == event_types.end(),
77 "CoreTiming Event \"{}\" is already registered. Events should only be registered "
78 "during Init to avoid breaking save states.",
79 name.c_str());
80 31
81 auto info = event_types.emplace(name, EventType{callback, nullptr}); 32 friend bool operator<(const Event& left, const Event& right) {
82 EventType* event_type = &info.first->second; 33 return std::tie(left.time, left.fifo_order) < std::tie(right.time, right.fifo_order);
83 event_type->name = &info.first->first; 34 }
84 return event_type; 35};
85}
86 36
87void UnregisterAllEvents() { 37CoreTiming::CoreTiming() = default;
88 ASSERT_MSG(event_queue.empty(), "Cannot unregister events with events pending"); 38CoreTiming::~CoreTiming() = default;
89 event_types.clear();
90}
91 39
92void Init() { 40void CoreTiming::Initialize() {
93 downcount = MAX_SLICE_LENGTH; 41 downcount = MAX_SLICE_LENGTH;
94 slice_length = MAX_SLICE_LENGTH; 42 slice_length = MAX_SLICE_LENGTH;
95 global_timer = 0; 43 global_timer = 0;
96 idled_cycles = 0; 44 idled_cycles = 0;
97 45
98 // The time between CoreTiming being intialized and the first call to Advance() is considered 46 // The time between CoreTiming being initialized and the first call to Advance() is considered
99 // the slice boundary between slice -1 and slice 0. Dispatcher loops must call Advance() before 47 // the slice boundary between slice -1 and slice 0. Dispatcher loops must call Advance() before
100 // executing the first cycle of each slice to prepare the slice length and downcount for 48 // executing the first cycle of each slice to prepare the slice length and downcount for
101 // that slice. 49 // that slice.
@@ -107,50 +55,51 @@ void Init() {
107 ev_lost = RegisterEvent("_lost_event", empty_timed_callback); 55 ev_lost = RegisterEvent("_lost_event", empty_timed_callback);
108} 56}
109 57
110void Shutdown() { 58void CoreTiming::Shutdown() {
111 MoveEvents(); 59 MoveEvents();
112 ClearPendingEvents(); 60 ClearPendingEvents();
113 UnregisterAllEvents(); 61 UnregisterAllEvents();
114} 62}
115 63
116// This should only be called from the CPU thread. If you are calling 64EventType* CoreTiming::RegisterEvent(const std::string& name, TimedCallback callback) {
117// it from any other thread, you are doing something evil 65 // check for existing type with same name.
118u64 GetTicks() { 66 // we want event type names to remain unique so that we can use them for serialization.
119 u64 ticks = static_cast<u64>(global_timer); 67 ASSERT_MSG(event_types.find(name) == event_types.end(),
120 if (!is_global_timer_sane) { 68 "CoreTiming Event \"{}\" is already registered. Events should only be registered "
121 ticks += slice_length - downcount; 69 "during Init to avoid breaking save states.",
122 } 70 name.c_str());
123 return ticks;
124}
125
126void AddTicks(u64 ticks) {
127 downcount -= static_cast<int>(ticks);
128}
129 71
130u64 GetIdleTicks() { 72 auto info = event_types.emplace(name, EventType{callback, nullptr});
131 return static_cast<u64>(idled_cycles); 73 EventType* event_type = &info.first->second;
74 event_type->name = &info.first->first;
75 return event_type;
132} 76}
133 77
134void ClearPendingEvents() { 78void CoreTiming::UnregisterAllEvents() {
135 event_queue.clear(); 79 ASSERT_MSG(event_queue.empty(), "Cannot unregister events with events pending");
80 event_types.clear();
136} 81}
137 82
138void ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 userdata) { 83void CoreTiming::ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 userdata) {
139 ASSERT(event_type != nullptr); 84 ASSERT(event_type != nullptr);
140 s64 timeout = GetTicks() + cycles_into_future; 85 const s64 timeout = GetTicks() + cycles_into_future;
86
141 // If this event needs to be scheduled before the next advance(), force one early 87 // If this event needs to be scheduled before the next advance(), force one early
142 if (!is_global_timer_sane) 88 if (!is_global_timer_sane) {
143 ForceExceptionCheck(cycles_into_future); 89 ForceExceptionCheck(cycles_into_future);
90 }
91
144 event_queue.emplace_back(Event{timeout, event_fifo_id++, userdata, event_type}); 92 event_queue.emplace_back(Event{timeout, event_fifo_id++, userdata, event_type});
145 std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>()); 93 std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
146} 94}
147 95
148void ScheduleEventThreadsafe(s64 cycles_into_future, const EventType* event_type, u64 userdata) { 96void CoreTiming::ScheduleEventThreadsafe(s64 cycles_into_future, const EventType* event_type,
97 u64 userdata) {
149 ts_queue.Push(Event{global_timer + cycles_into_future, 0, userdata, event_type}); 98 ts_queue.Push(Event{global_timer + cycles_into_future, 0, userdata, event_type});
150} 99}
151 100
152void UnscheduleEvent(const EventType* event_type, u64 userdata) { 101void CoreTiming::UnscheduleEvent(const EventType* event_type, u64 userdata) {
153 auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) { 102 const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) {
154 return e.type == event_type && e.userdata == userdata; 103 return e.type == event_type && e.userdata == userdata;
155 }); 104 });
156 105
@@ -161,13 +110,33 @@ void UnscheduleEvent(const EventType* event_type, u64 userdata) {
161 } 110 }
162} 111}
163 112
164void UnscheduleEventThreadsafe(const EventType* event_type, u64 userdata) { 113void CoreTiming::UnscheduleEventThreadsafe(const EventType* event_type, u64 userdata) {
165 unschedule_queue.Push(std::make_pair(event_type, userdata)); 114 unschedule_queue.Push(std::make_pair(event_type, userdata));
166} 115}
167 116
168void RemoveEvent(const EventType* event_type) { 117u64 CoreTiming::GetTicks() const {
169 auto itr = std::remove_if(event_queue.begin(), event_queue.end(), 118 u64 ticks = static_cast<u64>(global_timer);
170 [&](const Event& e) { return e.type == event_type; }); 119 if (!is_global_timer_sane) {
120 ticks += slice_length - downcount;
121 }
122 return ticks;
123}
124
125u64 CoreTiming::GetIdleTicks() const {
126 return static_cast<u64>(idled_cycles);
127}
128
129void CoreTiming::AddTicks(u64 ticks) {
130 downcount -= static_cast<int>(ticks);
131}
132
133void CoreTiming::ClearPendingEvents() {
134 event_queue.clear();
135}
136
137void CoreTiming::RemoveEvent(const EventType* event_type) {
138 const auto itr = std::remove_if(event_queue.begin(), event_queue.end(),
139 [&](const Event& e) { return e.type == event_type; });
171 140
172 // Removing random items breaks the invariant so we have to re-establish it. 141 // Removing random items breaks the invariant so we have to re-establish it.
173 if (itr != event_queue.end()) { 142 if (itr != event_queue.end()) {
@@ -176,22 +145,24 @@ void RemoveEvent(const EventType* event_type) {
176 } 145 }
177} 146}
178 147
179void RemoveNormalAndThreadsafeEvent(const EventType* event_type) { 148void CoreTiming::RemoveNormalAndThreadsafeEvent(const EventType* event_type) {
180 MoveEvents(); 149 MoveEvents();
181 RemoveEvent(event_type); 150 RemoveEvent(event_type);
182} 151}
183 152
184void ForceExceptionCheck(s64 cycles) { 153void CoreTiming::ForceExceptionCheck(s64 cycles) {
185 cycles = std::max<s64>(0, cycles); 154 cycles = std::max<s64>(0, cycles);
186 if (downcount > cycles) { 155 if (downcount <= cycles) {
187 // downcount is always (much) smaller than MAX_INT so we can safely cast cycles to an int 156 return;
188 // here. Account for cycles already executed by adjusting the g.slice_length
189 slice_length -= downcount - static_cast<int>(cycles);
190 downcount = static_cast<int>(cycles);
191 } 157 }
158
159 // downcount is always (much) smaller than MAX_INT so we can safely cast cycles to an int
160 // here. Account for cycles already executed by adjusting the g.slice_length
161 slice_length -= downcount - static_cast<int>(cycles);
162 downcount = static_cast<int>(cycles);
192} 163}
193 164
194void MoveEvents() { 165void CoreTiming::MoveEvents() {
195 for (Event ev; ts_queue.Pop(ev);) { 166 for (Event ev; ts_queue.Pop(ev);) {
196 ev.fifo_order = event_fifo_id++; 167 ev.fifo_order = event_fifo_id++;
197 event_queue.emplace_back(std::move(ev)); 168 event_queue.emplace_back(std::move(ev));
@@ -199,13 +170,13 @@ void MoveEvents() {
199 } 170 }
200} 171}
201 172
202void Advance() { 173void CoreTiming::Advance() {
203 MoveEvents(); 174 MoveEvents();
204 for (std::pair<const EventType*, u64> ev; unschedule_queue.Pop(ev);) { 175 for (std::pair<const EventType*, u64> ev; unschedule_queue.Pop(ev);) {
205 UnscheduleEvent(ev.first, ev.second); 176 UnscheduleEvent(ev.first, ev.second);
206 } 177 }
207 178
208 int cycles_executed = slice_length - downcount; 179 const int cycles_executed = slice_length - downcount;
209 global_timer += cycles_executed; 180 global_timer += cycles_executed;
210 slice_length = MAX_SLICE_LENGTH; 181 slice_length = MAX_SLICE_LENGTH;
211 182
@@ -229,16 +200,16 @@ void Advance() {
229 downcount = slice_length; 200 downcount = slice_length;
230} 201}
231 202
232void Idle() { 203void CoreTiming::Idle() {
233 idled_cycles += downcount; 204 idled_cycles += downcount;
234 downcount = 0; 205 downcount = 0;
235} 206}
236 207
237std::chrono::microseconds GetGlobalTimeUs() { 208std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const {
238 return std::chrono::microseconds{GetTicks() * 1000000 / BASE_CLOCK_RATE}; 209 return std::chrono::microseconds{GetTicks() * 1000000 / BASE_CLOCK_RATE};
239} 210}
240 211
241int GetDowncount() { 212int CoreTiming::GetDowncount() const {
242 return downcount; 213 return downcount;
243} 214}
244 215
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index 093989d4c..59163bae1 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -4,92 +4,153 @@
4 4
5#pragma once 5#pragma once
6 6
7/**
8 * This is a system to schedule events into the emulated machine's future. Time is measured
9 * in main CPU clock cycles.
10 *
11 * To schedule an event, you first have to register its type. This is where you pass in the
12 * callback. You then schedule events using the type id you get back.
13 *
14 * The int cyclesLate that the callbacks get is how many cycles late it was.
15 * So to schedule a new event on a regular basis:
16 * inside callback:
17 * ScheduleEvent(periodInCycles - cyclesLate, callback, "whatever")
18 */
19
20#include <chrono> 7#include <chrono>
21#include <functional> 8#include <functional>
22#include <string> 9#include <string>
10#include <unordered_map>
11#include <vector>
23#include "common/common_types.h" 12#include "common/common_types.h"
13#include "common/threadsafe_queue.h"
24 14
25namespace Core::Timing { 15namespace Core::Timing {
26 16
27struct EventType; 17/// A callback that may be scheduled for a particular core timing event.
28
29using TimedCallback = std::function<void(u64 userdata, int cycles_late)>; 18using TimedCallback = std::function<void(u64 userdata, int cycles_late)>;
30 19
31/** 20/// Contains the characteristics of a particular event.
32 * CoreTiming begins at the boundary of timing slice -1. An initial call to Advance() is 21struct EventType {
33 * required to end slice -1 and start slice 0 before the first cycle of code is executed. 22 /// The event's callback function.
34 */ 23 TimedCallback callback;
35void Init(); 24 /// A pointer to the name of the event.
36void Shutdown(); 25 const std::string* name;
37 26};
38/**
39 * This should only be called from the emu thread, if you are calling it any other thread, you are
40 * doing something evil
41 */
42u64 GetTicks();
43u64 GetIdleTicks();
44void AddTicks(u64 ticks);
45
46/**
47 * Returns the event_type identifier. if name is not unique, it will assert.
48 */
49EventType* RegisterEvent(const std::string& name, TimedCallback callback);
50void UnregisterAllEvents();
51
52/**
53 * After the first Advance, the slice lengths and the downcount will be reduced whenever an event
54 * is scheduled earlier than the current values.
55 * Scheduling from a callback will not update the downcount until the Advance() completes.
56 */
57void ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 userdata = 0);
58 27
59/** 28/**
60 * This is to be called when outside of hle threads, such as the graphics thread, wants to 29 * This is a system to schedule events into the emulated machine's future. Time is measured
61 * schedule things to be executed on the main thread. 30 * in main CPU clock cycles.
62 * Not that this doesn't change slice_length and thus events scheduled by this might be called 31 *
63 * with a delay of up to MAX_SLICE_LENGTH 32 * To schedule an event, you first have to register its type. This is where you pass in the
64 */ 33 * callback. You then schedule events using the type id you get back.
65void ScheduleEventThreadsafe(s64 cycles_into_future, const EventType* event_type, u64 userdata); 34 *
66 35 * The int cyclesLate that the callbacks get is how many cycles late it was.
67void UnscheduleEvent(const EventType* event_type, u64 userdata); 36 * So to schedule a new event on a regular basis:
68void UnscheduleEventThreadsafe(const EventType* event_type, u64 userdata); 37 * inside callback:
69 38 * ScheduleEvent(periodInCycles - cyclesLate, callback, "whatever")
70/// We only permit one event of each type in the queue at a time.
71void RemoveEvent(const EventType* event_type);
72void RemoveNormalAndThreadsafeEvent(const EventType* event_type);
73
74/** Advance must be called at the beginning of dispatcher loops, not the end. Advance() ends
75 * the previous timing slice and begins the next one, you must Advance from the previous
76 * slice to the current one before executing any cycles. CoreTiming starts in slice -1 so an
77 * Advance() is required to initialize the slice length before the first cycle of emulated
78 * instructions is executed.
79 */ 39 */
80void Advance(); 40class CoreTiming {
81void MoveEvents(); 41public:
82 42 CoreTiming();
83/// Pretend that the main CPU has executed enough cycles to reach the next event. 43 ~CoreTiming();
84void Idle(); 44
85 45 CoreTiming(const CoreTiming&) = delete;
86/// Clear all pending events. This should ONLY be done on exit. 46 CoreTiming(CoreTiming&&) = delete;
87void ClearPendingEvents(); 47
88 48 CoreTiming& operator=(const CoreTiming&) = delete;
89void ForceExceptionCheck(s64 cycles); 49 CoreTiming& operator=(CoreTiming&&) = delete;
90 50
91std::chrono::microseconds GetGlobalTimeUs(); 51 /// CoreTiming begins at the boundary of timing slice -1. An initial call to Advance() is
92 52 /// required to end slice - 1 and start slice 0 before the first cycle of code is executed.
93int GetDowncount(); 53 void Initialize();
54
55 /// Tears down all timing related functionality.
56 void Shutdown();
57
58 /// Registers a core timing event with the given name and callback.
59 ///
60 /// @param name The name of the core timing event to register.
61 /// @param callback The callback to execute for the event.
62 ///
63 /// @returns An EventType instance representing the registered event.
64 ///
65 /// @pre The name of the event being registered must be unique among all
66 /// registered events.
67 ///
68 EventType* RegisterEvent(const std::string& name, TimedCallback callback);
69
70 /// Unregisters all registered events thus far.
71 void UnregisterAllEvents();
72
73 /// After the first Advance, the slice lengths and the downcount will be reduced whenever an
74 /// event is scheduled earlier than the current values.
75 ///
76 /// Scheduling from a callback will not update the downcount until the Advance() completes.
77 void ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 userdata = 0);
78
79 /// This is to be called when outside of hle threads, such as the graphics thread, wants to
80 /// schedule things to be executed on the main thread.
81 ///
82 /// @note This doesn't change slice_length and thus events scheduled by this might be
83 /// called with a delay of up to MAX_SLICE_LENGTH
84 void ScheduleEventThreadsafe(s64 cycles_into_future, const EventType* event_type,
85 u64 userdata = 0);
86
87 void UnscheduleEvent(const EventType* event_type, u64 userdata);
88 void UnscheduleEventThreadsafe(const EventType* event_type, u64 userdata);
89
90 /// We only permit one event of each type in the queue at a time.
91 void RemoveEvent(const EventType* event_type);
92 void RemoveNormalAndThreadsafeEvent(const EventType* event_type);
93
94 void ForceExceptionCheck(s64 cycles);
95
96 /// This should only be called from the emu thread, if you are calling it any other thread,
97 /// you are doing something evil
98 u64 GetTicks() const;
99
100 u64 GetIdleTicks() const;
101
102 void AddTicks(u64 ticks);
103
104 /// Advance must be called at the beginning of dispatcher loops, not the end. Advance() ends
105 /// the previous timing slice and begins the next one, you must Advance from the previous
106 /// slice to the current one before executing any cycles. CoreTiming starts in slice -1 so an
107 /// Advance() is required to initialize the slice length before the first cycle of emulated
108 /// instructions is executed.
109 void Advance();
110
111 /// Pretend that the main CPU has executed enough cycles to reach the next event.
112 void Idle();
113
114 std::chrono::microseconds GetGlobalTimeUs() const;
115
116 int GetDowncount() const;
117
118private:
119 struct Event;
120
121 /// Clear all pending events. This should ONLY be done on exit.
122 void ClearPendingEvents();
123 void MoveEvents();
124
125 s64 global_timer = 0;
126 s64 idled_cycles = 0;
127 int slice_length = 0;
128 int downcount = 0;
129
130 // Are we in a function that has been called from Advance()
131 // If events are scheduled from a function that gets called from Advance(),
132 // don't change slice_length and downcount.
133 bool is_global_timer_sane = false;
134
135 // The queue is a min-heap using std::make_heap/push_heap/pop_heap.
136 // We don't use std::priority_queue because we need to be able to serialize, unserialize and
137 // erase arbitrary events (RemoveEvent()) regardless of the queue order. These aren't
138 // accomodated by the standard adaptor class.
139 std::vector<Event> event_queue;
140 u64 event_fifo_id = 0;
141
142 // Stores each element separately as a linked list node so pointers to elements
143 // remain stable regardless of rehashes/resizing.
144 std::unordered_map<std::string, EventType> event_types;
145
146 // The queue for storing the events from other threads threadsafe until they will be added
147 // to the event_queue by the emu thread
148 Common::MPSCQueue<Event> ts_queue;
149
150 // The queue for unscheduling the events from other threads threadsafe
151 Common::MPSCQueue<std::pair<const EventType*, u64>> unschedule_queue;
152
153 EventType* ev_lost = nullptr;
154};
94 155
95} // namespace Core::Timing 156} // namespace Core::Timing
diff --git a/src/core/cpu_core_manager.cpp b/src/core/cpu_core_manager.cpp
index 769a6fefa..2ddb3610d 100644
--- a/src/core/cpu_core_manager.cpp
+++ b/src/core/cpu_core_manager.cpp
@@ -27,7 +27,8 @@ void CpuCoreManager::Initialize(System& system) {
27 exclusive_monitor = Cpu::MakeExclusiveMonitor(cores.size()); 27 exclusive_monitor = Cpu::MakeExclusiveMonitor(cores.size());
28 28
29 for (std::size_t index = 0; index < cores.size(); ++index) { 29 for (std::size_t index = 0; index < cores.size(); ++index) {
30 cores[index] = std::make_unique<Cpu>(*exclusive_monitor, *barrier, index); 30 cores[index] =
31 std::make_unique<Cpu>(system.CoreTiming(), *exclusive_monitor, *barrier, index);
31 } 32 }
32 33
33 // Create threads for CPU cores 1-3, and build thread_to_cpu map 34 // Create threads for CPU cores 1-3, and build thread_to_cpu map
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 3721ae8fe..dd749eed4 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -86,11 +86,11 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] int cycles_
86} 86}
87 87
88struct KernelCore::Impl { 88struct KernelCore::Impl {
89 void Initialize(KernelCore& kernel) { 89 void Initialize(KernelCore& kernel, Core::Timing::CoreTiming& core_timing) {
90 Shutdown(); 90 Shutdown();
91 91
92 InitializeSystemResourceLimit(kernel); 92 InitializeSystemResourceLimit(kernel);
93 InitializeThreads(); 93 InitializeThreads(core_timing);
94 } 94 }
95 95
96 void Shutdown() { 96 void Shutdown() {
@@ -122,9 +122,9 @@ struct KernelCore::Impl {
122 ASSERT(system_resource_limit->SetLimitValue(ResourceType::Sessions, 900).IsSuccess()); 122 ASSERT(system_resource_limit->SetLimitValue(ResourceType::Sessions, 900).IsSuccess());
123 } 123 }
124 124
125 void InitializeThreads() { 125 void InitializeThreads(Core::Timing::CoreTiming& core_timing) {
126 thread_wakeup_event_type = 126 thread_wakeup_event_type =
127 Core::Timing::RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback); 127 core_timing.RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback);
128 } 128 }
129 129
130 std::atomic<u32> next_object_id{0}; 130 std::atomic<u32> next_object_id{0};
@@ -152,8 +152,8 @@ KernelCore::~KernelCore() {
152 Shutdown(); 152 Shutdown();
153} 153}
154 154
155void KernelCore::Initialize() { 155void KernelCore::Initialize(Core::Timing::CoreTiming& core_timing) {
156 impl->Initialize(*this); 156 impl->Initialize(*this, core_timing);
157} 157}
158 158
159void KernelCore::Shutdown() { 159void KernelCore::Shutdown() {
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 7406f107e..154bced42 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -12,8 +12,9 @@ template <typename T>
12class ResultVal; 12class ResultVal;
13 13
14namespace Core::Timing { 14namespace Core::Timing {
15class CoreTiming;
15struct EventType; 16struct EventType;
16} 17} // namespace Core::Timing
17 18
18namespace Kernel { 19namespace Kernel {
19 20
@@ -39,7 +40,11 @@ public:
39 KernelCore& operator=(KernelCore&&) = delete; 40 KernelCore& operator=(KernelCore&&) = delete;
40 41
41 /// Resets the kernel to a clean slate for use. 42 /// Resets the kernel to a clean slate for use.
42 void Initialize(); 43 ///
44 /// @param core_timing CoreTiming instance used to create any necessary
45 /// kernel-specific callback events.
46 ///
47 void Initialize(Core::Timing::CoreTiming& core_timing);
43 48
44 /// Clears all resources in use by the kernel instance. 49 /// Clears all resources in use by the kernel instance.
45 void Shutdown(); 50 void Shutdown();
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp
index 9e2517e1b..44f30d070 100644
--- a/src/core/hle/kernel/scheduler.cpp
+++ b/src/core/hle/kernel/scheduler.cpp
@@ -111,7 +111,7 @@ void Scheduler::SwitchContext(Thread* new_thread) {
111 111
112void Scheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) { 112void Scheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) {
113 const u64 prev_switch_ticks = last_context_switch_time; 113 const u64 prev_switch_ticks = last_context_switch_time;
114 const u64 most_recent_switch_ticks = Core::Timing::GetTicks(); 114 const u64 most_recent_switch_ticks = Core::System::GetInstance().CoreTiming().GetTicks();
115 const u64 update_ticks = most_recent_switch_ticks - prev_switch_ticks; 115 const u64 update_ticks = most_recent_switch_ticks - prev_switch_ticks;
116 116
117 if (thread != nullptr) { 117 if (thread != nullptr) {
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 5f040f79f..c5d399bab 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -918,6 +918,7 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
918 } 918 }
919 919
920 const auto& system = Core::System::GetInstance(); 920 const auto& system = Core::System::GetInstance();
921 const auto& core_timing = system.CoreTiming();
921 const auto& scheduler = system.CurrentScheduler(); 922 const auto& scheduler = system.CurrentScheduler();
922 const auto* const current_thread = scheduler.GetCurrentThread(); 923 const auto* const current_thread = scheduler.GetCurrentThread();
923 const bool same_thread = current_thread == thread; 924 const bool same_thread = current_thread == thread;
@@ -927,9 +928,9 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
927 if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) { 928 if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) {
928 const u64 thread_ticks = current_thread->GetTotalCPUTimeTicks(); 929 const u64 thread_ticks = current_thread->GetTotalCPUTimeTicks();
929 930
930 out_ticks = thread_ticks + (Core::Timing::GetTicks() - prev_ctx_ticks); 931 out_ticks = thread_ticks + (core_timing.GetTicks() - prev_ctx_ticks);
931 } else if (same_thread && info_sub_id == system.CurrentCoreIndex()) { 932 } else if (same_thread && info_sub_id == system.CurrentCoreIndex()) {
932 out_ticks = Core::Timing::GetTicks() - prev_ctx_ticks; 933 out_ticks = core_timing.GetTicks() - prev_ctx_ticks;
933 } 934 }
934 935
935 *result = out_ticks; 936 *result = out_ticks;
@@ -1546,10 +1547,11 @@ static ResultCode SignalToAddress(VAddr address, u32 type, s32 value, s32 num_to
1546static u64 GetSystemTick() { 1547static u64 GetSystemTick() {
1547 LOG_TRACE(Kernel_SVC, "called"); 1548 LOG_TRACE(Kernel_SVC, "called");
1548 1549
1549 const u64 result{Core::Timing::GetTicks()}; 1550 auto& core_timing = Core::System::GetInstance().CoreTiming();
1551 const u64 result{core_timing.GetTicks()};
1550 1552
1551 // Advance time to defeat dumb games that busy-wait for the frame to end. 1553 // Advance time to defeat dumb games that busy-wait for the frame to end.
1552 Core::Timing::AddTicks(400); 1554 core_timing.AddTicks(400);
1553 1555
1554 return result; 1556 return result;
1555} 1557}
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 7881c2b90..6661e2130 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -43,7 +43,8 @@ Thread::~Thread() = default;
43 43
44void Thread::Stop() { 44void Thread::Stop() {
45 // Cancel any outstanding wakeup events for this thread 45 // Cancel any outstanding wakeup events for this thread
46 Core::Timing::UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), callback_handle); 46 Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(),
47 callback_handle);
47 kernel.ThreadWakeupCallbackHandleTable().Close(callback_handle); 48 kernel.ThreadWakeupCallbackHandleTable().Close(callback_handle);
48 callback_handle = 0; 49 callback_handle = 0;
49 50
@@ -85,13 +86,14 @@ void Thread::WakeAfterDelay(s64 nanoseconds) {
85 86
86 // This function might be called from any thread so we have to be cautious and use the 87 // This function might be called from any thread so we have to be cautious and use the
87 // thread-safe version of ScheduleEvent. 88 // thread-safe version of ScheduleEvent.
88 Core::Timing::ScheduleEventThreadsafe(Core::Timing::nsToCycles(nanoseconds), 89 Core::System::GetInstance().CoreTiming().ScheduleEventThreadsafe(
89 kernel.ThreadWakeupCallbackEventType(), callback_handle); 90 Core::Timing::nsToCycles(nanoseconds), kernel.ThreadWakeupCallbackEventType(),
91 callback_handle);
90} 92}
91 93
92void Thread::CancelWakeupTimer() { 94void Thread::CancelWakeupTimer() {
93 Core::Timing::UnscheduleEventThreadsafe(kernel.ThreadWakeupCallbackEventType(), 95 Core::System::GetInstance().CoreTiming().UnscheduleEventThreadsafe(
94 callback_handle); 96 kernel.ThreadWakeupCallbackEventType(), callback_handle);
95} 97}
96 98
97static std::optional<s32> GetNextProcessorId(u64 mask) { 99static std::optional<s32> GetNextProcessorId(u64 mask) {
@@ -190,6 +192,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name
190 return ResultCode(-1); 192 return ResultCode(-1);
191 } 193 }
192 194
195 auto& system = Core::System::GetInstance();
193 SharedPtr<Thread> thread(new Thread(kernel)); 196 SharedPtr<Thread> thread(new Thread(kernel));
194 197
195 thread->thread_id = kernel.CreateNewThreadID(); 198 thread->thread_id = kernel.CreateNewThreadID();
@@ -198,7 +201,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name
198 thread->stack_top = stack_top; 201 thread->stack_top = stack_top;
199 thread->tpidr_el0 = 0; 202 thread->tpidr_el0 = 0;
200 thread->nominal_priority = thread->current_priority = priority; 203 thread->nominal_priority = thread->current_priority = priority;
201 thread->last_running_ticks = Core::Timing::GetTicks(); 204 thread->last_running_ticks = system.CoreTiming().GetTicks();
202 thread->processor_id = processor_id; 205 thread->processor_id = processor_id;
203 thread->ideal_core = processor_id; 206 thread->ideal_core = processor_id;
204 thread->affinity_mask = 1ULL << processor_id; 207 thread->affinity_mask = 1ULL << processor_id;
@@ -209,7 +212,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name
209 thread->name = std::move(name); 212 thread->name = std::move(name);
210 thread->callback_handle = kernel.ThreadWakeupCallbackHandleTable().Create(thread).Unwrap(); 213 thread->callback_handle = kernel.ThreadWakeupCallbackHandleTable().Create(thread).Unwrap();
211 thread->owner_process = &owner_process; 214 thread->owner_process = &owner_process;
212 thread->scheduler = &Core::System::GetInstance().Scheduler(processor_id); 215 thread->scheduler = &system.Scheduler(processor_id);
213 thread->scheduler->AddThread(thread, priority); 216 thread->scheduler->AddThread(thread, priority);
214 thread->tls_address = thread->owner_process->MarkNextAvailableTLSSlotAsUsed(*thread); 217 thread->tls_address = thread->owner_process->MarkNextAvailableTLSSlotAsUsed(*thread);
215 218
@@ -258,7 +261,7 @@ void Thread::SetStatus(ThreadStatus new_status) {
258 } 261 }
259 262
260 if (status == ThreadStatus::Running) { 263 if (status == ThreadStatus::Running) {
261 last_running_ticks = Core::Timing::GetTicks(); 264 last_running_ticks = Core::System::GetInstance().CoreTiming().GetTicks();
262 } 265 }
263 266
264 status = new_status; 267 status = new_status;
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
index dc6a6b188..6831c0735 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -68,12 +68,12 @@ public:
68 RegisterHandlers(functions); 68 RegisterHandlers(functions);
69 69
70 // This is the event handle used to check if the audio buffer was released 70 // This is the event handle used to check if the audio buffer was released
71 auto& kernel = Core::System::GetInstance().Kernel(); 71 auto& system = Core::System::GetInstance();
72 buffer_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky, 72 buffer_event = Kernel::WritableEvent::CreateEventPair(
73 "IAudioOutBufferReleased"); 73 system.Kernel(), Kernel::ResetType::Sticky, "IAudioOutBufferReleased");
74 74
75 stream = audio_core.OpenStream(audio_params.sample_rate, audio_params.channel_count, 75 stream = audio_core.OpenStream(system.CoreTiming(), audio_params.sample_rate,
76 std::move(unique_name), 76 audio_params.channel_count, std::move(unique_name),
77 [=]() { buffer_event.writable->Signal(); }); 77 [=]() { buffer_event.writable->Signal(); });
78 } 78 }
79 79
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index 76cc48254..7e0cc64a8 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -42,10 +42,11 @@ public:
42 // clang-format on 42 // clang-format on
43 RegisterHandlers(functions); 43 RegisterHandlers(functions);
44 44
45 auto& kernel = Core::System::GetInstance().Kernel(); 45 auto& system = Core::System::GetInstance();
46 system_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky, 46 system_event = Kernel::WritableEvent::CreateEventPair(
47 "IAudioRenderer:SystemEvent"); 47 system.Kernel(), Kernel::ResetType::Sticky, "IAudioRenderer:SystemEvent");
48 renderer = std::make_unique<AudioCore::AudioRenderer>(audren_params, system_event.writable); 48 renderer = std::make_unique<AudioCore::AudioRenderer>(system.CoreTiming(), audren_params,
49 system_event.writable);
49 } 50 }
50 51
51private: 52private:
diff --git a/src/core/hle/service/hid/controllers/controller_base.h b/src/core/hle/service/hid/controllers/controller_base.h
index f0e092b1b..5e5097a03 100644
--- a/src/core/hle/service/hid/controllers/controller_base.h
+++ b/src/core/hle/service/hid/controllers/controller_base.h
@@ -7,6 +7,10 @@
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "common/swap.h" 8#include "common/swap.h"
9 9
10namespace Core::Timing {
11class CoreTiming;
12}
13
10namespace Service::HID { 14namespace Service::HID {
11class ControllerBase { 15class ControllerBase {
12public: 16public:
@@ -20,7 +24,8 @@ public:
20 virtual void OnRelease() = 0; 24 virtual void OnRelease() = 0;
21 25
22 // When the controller is requesting an update for the shared memory 26 // When the controller is requesting an update for the shared memory
23 virtual void OnUpdate(u8* data, std::size_t size) = 0; 27 virtual void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
28 std::size_t size) = 0;
24 29
25 // Called when input devices should be loaded 30 // Called when input devices should be loaded
26 virtual void OnLoadInputDevices() = 0; 31 virtual void OnLoadInputDevices() = 0;
diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp
index b264c9503..c5c2e032a 100644
--- a/src/core/hle/service/hid/controllers/debug_pad.cpp
+++ b/src/core/hle/service/hid/controllers/debug_pad.cpp
@@ -21,8 +21,9 @@ void Controller_DebugPad::OnInit() {}
21 21
22void Controller_DebugPad::OnRelease() {} 22void Controller_DebugPad::OnRelease() {}
23 23
24void Controller_DebugPad::OnUpdate(u8* data, std::size_t size) { 24void Controller_DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
25 shared_memory.header.timestamp = Core::Timing::GetTicks(); 25 std::size_t size) {
26 shared_memory.header.timestamp = core_timing.GetTicks();
26 shared_memory.header.total_entry_count = 17; 27 shared_memory.header.total_entry_count = 17;
27 28
28 if (!IsControllerActivated()) { 29 if (!IsControllerActivated()) {
diff --git a/src/core/hle/service/hid/controllers/debug_pad.h b/src/core/hle/service/hid/controllers/debug_pad.h
index 68b734248..929035034 100644
--- a/src/core/hle/service/hid/controllers/debug_pad.h
+++ b/src/core/hle/service/hid/controllers/debug_pad.h
@@ -26,7 +26,7 @@ public:
26 void OnRelease() override; 26 void OnRelease() override;
27 27
28 // When the controller is requesting an update for the shared memory 28 // When the controller is requesting an update for the shared memory
29 void OnUpdate(u8* data, std::size_t size) override; 29 void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
30 30
31 // Called when input devices should be loaded 31 // Called when input devices should be loaded
32 void OnLoadInputDevices() override; 32 void OnLoadInputDevices() override;
diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp
index 6d21f1a7d..a179252e3 100644
--- a/src/core/hle/service/hid/controllers/gesture.cpp
+++ b/src/core/hle/service/hid/controllers/gesture.cpp
@@ -17,8 +17,9 @@ void Controller_Gesture::OnInit() {}
17 17
18void Controller_Gesture::OnRelease() {} 18void Controller_Gesture::OnRelease() {}
19 19
20void Controller_Gesture::OnUpdate(u8* data, std::size_t size) { 20void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
21 shared_memory.header.timestamp = Core::Timing::GetTicks(); 21 std::size_t size) {
22 shared_memory.header.timestamp = core_timing.GetTicks();
22 shared_memory.header.total_entry_count = 17; 23 shared_memory.header.total_entry_count = 17;
23 24
24 if (!IsControllerActivated()) { 25 if (!IsControllerActivated()) {
diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h
index 1056ffbcd..f305fe90f 100644
--- a/src/core/hle/service/hid/controllers/gesture.h
+++ b/src/core/hle/service/hid/controllers/gesture.h
@@ -22,7 +22,7 @@ public:
22 void OnRelease() override; 22 void OnRelease() override;
23 23
24 // When the controller is requesting an update for the shared memory 24 // When the controller is requesting an update for the shared memory
25 void OnUpdate(u8* data, size_t size) override; 25 void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, size_t size) override;
26 26
27 // Called when input devices should be loaded 27 // Called when input devices should be loaded
28 void OnLoadInputDevices() override; 28 void OnLoadInputDevices() override;
diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp
index 798f30436..92d7bfb52 100644
--- a/src/core/hle/service/hid/controllers/keyboard.cpp
+++ b/src/core/hle/service/hid/controllers/keyboard.cpp
@@ -19,8 +19,9 @@ void Controller_Keyboard::OnInit() {}
19 19
20void Controller_Keyboard::OnRelease() {} 20void Controller_Keyboard::OnRelease() {}
21 21
22void Controller_Keyboard::OnUpdate(u8* data, std::size_t size) { 22void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
23 shared_memory.header.timestamp = Core::Timing::GetTicks(); 23 std::size_t size) {
24 shared_memory.header.timestamp = core_timing.GetTicks();
24 shared_memory.header.total_entry_count = 17; 25 shared_memory.header.total_entry_count = 17;
25 26
26 if (!IsControllerActivated()) { 27 if (!IsControllerActivated()) {
diff --git a/src/core/hle/service/hid/controllers/keyboard.h b/src/core/hle/service/hid/controllers/keyboard.h
index f52775456..73cd2c7bb 100644
--- a/src/core/hle/service/hid/controllers/keyboard.h
+++ b/src/core/hle/service/hid/controllers/keyboard.h
@@ -25,7 +25,7 @@ public:
25 void OnRelease() override; 25 void OnRelease() override;
26 26
27 // When the controller is requesting an update for the shared memory 27 // When the controller is requesting an update for the shared memory
28 void OnUpdate(u8* data, std::size_t size) override; 28 void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
29 29
30 // Called when input devices should be loaded 30 // Called when input devices should be loaded
31 void OnLoadInputDevices() override; 31 void OnLoadInputDevices() override;
diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp
index 4985037be..11ab096d9 100644
--- a/src/core/hle/service/hid/controllers/mouse.cpp
+++ b/src/core/hle/service/hid/controllers/mouse.cpp
@@ -17,8 +17,9 @@ Controller_Mouse::~Controller_Mouse() = default;
17void Controller_Mouse::OnInit() {} 17void Controller_Mouse::OnInit() {}
18void Controller_Mouse::OnRelease() {} 18void Controller_Mouse::OnRelease() {}
19 19
20void Controller_Mouse::OnUpdate(u8* data, std::size_t size) { 20void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
21 shared_memory.header.timestamp = Core::Timing::GetTicks(); 21 std::size_t size) {
22 shared_memory.header.timestamp = core_timing.GetTicks();
22 shared_memory.header.total_entry_count = 17; 23 shared_memory.header.total_entry_count = 17;
23 24
24 if (!IsControllerActivated()) { 25 if (!IsControllerActivated()) {
diff --git a/src/core/hle/service/hid/controllers/mouse.h b/src/core/hle/service/hid/controllers/mouse.h
index 70b654d07..9d46eecbe 100644
--- a/src/core/hle/service/hid/controllers/mouse.h
+++ b/src/core/hle/service/hid/controllers/mouse.h
@@ -24,7 +24,7 @@ public:
24 void OnRelease() override; 24 void OnRelease() override;
25 25
26 // When the controller is requesting an update for the shared memory 26 // When the controller is requesting an update for the shared memory
27 void OnUpdate(u8* data, std::size_t size) override; 27 void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
28 28
29 // Called when input devices should be loaded 29 // Called when input devices should be loaded
30 void OnLoadInputDevices() override; 30 void OnLoadInputDevices() override;
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index ffdd1c593..e7fc7a619 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -288,7 +288,8 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
288 rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX); 288 rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX);
289} 289}
290 290
291void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) { 291void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
292 std::size_t data_len) {
292 if (!IsControllerActivated()) 293 if (!IsControllerActivated())
293 return; 294 return;
294 for (std::size_t i = 0; i < shared_memory_entries.size(); i++) { 295 for (std::size_t i = 0; i < shared_memory_entries.size(); i++) {
@@ -308,7 +309,7 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) {
308 const auto& last_entry = 309 const auto& last_entry =
309 main_controller->npad[main_controller->common.last_entry_index]; 310 main_controller->npad[main_controller->common.last_entry_index];
310 311
311 main_controller->common.timestamp = Core::Timing::GetTicks(); 312 main_controller->common.timestamp = core_timing.GetTicks();
312 main_controller->common.last_entry_index = 313 main_controller->common.last_entry_index =
313 (main_controller->common.last_entry_index + 1) % 17; 314 (main_controller->common.last_entry_index + 1) % 17;
314 315
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 106cf58c8..18c7a94e6 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -30,7 +30,7 @@ public:
30 void OnRelease() override; 30 void OnRelease() override;
31 31
32 // When the controller is requesting an update for the shared memory 32 // When the controller is requesting an update for the shared memory
33 void OnUpdate(u8* data, std::size_t size) override; 33 void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
34 34
35 // Called when input devices should be loaded 35 // Called when input devices should be loaded
36 void OnLoadInputDevices() override; 36 void OnLoadInputDevices() override;
diff --git a/src/core/hle/service/hid/controllers/stubbed.cpp b/src/core/hle/service/hid/controllers/stubbed.cpp
index cca4dca1d..946948f5e 100644
--- a/src/core/hle/service/hid/controllers/stubbed.cpp
+++ b/src/core/hle/service/hid/controllers/stubbed.cpp
@@ -16,13 +16,14 @@ void Controller_Stubbed::OnInit() {}
16 16
17void Controller_Stubbed::OnRelease() {} 17void Controller_Stubbed::OnRelease() {}
18 18
19void Controller_Stubbed::OnUpdate(u8* data, std::size_t size) { 19void Controller_Stubbed::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
20 std::size_t size) {
20 if (!smart_update) { 21 if (!smart_update) {
21 return; 22 return;
22 } 23 }
23 24
24 CommonHeader header{}; 25 CommonHeader header{};
25 header.timestamp = Core::Timing::GetTicks(); 26 header.timestamp = core_timing.GetTicks();
26 header.total_entry_count = 17; 27 header.total_entry_count = 17;
27 header.entry_count = 0; 28 header.entry_count = 0;
28 header.last_entry_index = 0; 29 header.last_entry_index = 0;
diff --git a/src/core/hle/service/hid/controllers/stubbed.h b/src/core/hle/service/hid/controllers/stubbed.h
index 4a21c643e..24469f03e 100644
--- a/src/core/hle/service/hid/controllers/stubbed.h
+++ b/src/core/hle/service/hid/controllers/stubbed.h
@@ -20,7 +20,7 @@ public:
20 void OnRelease() override; 20 void OnRelease() override;
21 21
22 // When the controller is requesting an update for the shared memory 22 // When the controller is requesting an update for the shared memory
23 void OnUpdate(u8* data, std::size_t size) override; 23 void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
24 24
25 // Called when input devices should be loaded 25 // Called when input devices should be loaded
26 void OnLoadInputDevices() override; 26 void OnLoadInputDevices() override;
diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp
index a7c8acc72..1a8445a43 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.cpp
+++ b/src/core/hle/service/hid/controllers/touchscreen.cpp
@@ -20,8 +20,9 @@ void Controller_Touchscreen::OnInit() {}
20 20
21void Controller_Touchscreen::OnRelease() {} 21void Controller_Touchscreen::OnRelease() {}
22 22
23void Controller_Touchscreen::OnUpdate(u8* data, std::size_t size) { 23void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
24 shared_memory.header.timestamp = Core::Timing::GetTicks(); 24 std::size_t size) {
25 shared_memory.header.timestamp = core_timing.GetTicks();
25 shared_memory.header.total_entry_count = 17; 26 shared_memory.header.total_entry_count = 17;
26 27
27 if (!IsControllerActivated()) { 28 if (!IsControllerActivated()) {
@@ -48,7 +49,7 @@ void Controller_Touchscreen::OnUpdate(u8* data, std::size_t size) {
48 touch_entry.diameter_x = Settings::values.touchscreen.diameter_x; 49 touch_entry.diameter_x = Settings::values.touchscreen.diameter_x;
49 touch_entry.diameter_y = Settings::values.touchscreen.diameter_y; 50 touch_entry.diameter_y = Settings::values.touchscreen.diameter_y;
50 touch_entry.rotation_angle = Settings::values.touchscreen.rotation_angle; 51 touch_entry.rotation_angle = Settings::values.touchscreen.rotation_angle;
51 const u64 tick = Core::Timing::GetTicks(); 52 const u64 tick = core_timing.GetTicks();
52 touch_entry.delta_time = tick - last_touch; 53 touch_entry.delta_time = tick - last_touch;
53 last_touch = tick; 54 last_touch = tick;
54 touch_entry.finger = Settings::values.touchscreen.finger; 55 touch_entry.finger = Settings::values.touchscreen.finger;
diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h
index 94cd0eba9..012b6e0dd 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.h
+++ b/src/core/hle/service/hid/controllers/touchscreen.h
@@ -24,7 +24,7 @@ public:
24 void OnRelease() override; 24 void OnRelease() override;
25 25
26 // When the controller is requesting an update for the shared memory 26 // When the controller is requesting an update for the shared memory
27 void OnUpdate(u8* data, std::size_t size) override; 27 void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
28 28
29 // Called when input devices should be loaded 29 // Called when input devices should be loaded
30 void OnLoadInputDevices() override; 30 void OnLoadInputDevices() override;
diff --git a/src/core/hle/service/hid/controllers/xpad.cpp b/src/core/hle/service/hid/controllers/xpad.cpp
index eff03d14e..1a9da9576 100644
--- a/src/core/hle/service/hid/controllers/xpad.cpp
+++ b/src/core/hle/service/hid/controllers/xpad.cpp
@@ -17,9 +17,10 @@ void Controller_XPad::OnInit() {}
17 17
18void Controller_XPad::OnRelease() {} 18void Controller_XPad::OnRelease() {}
19 19
20void Controller_XPad::OnUpdate(u8* data, std::size_t size) { 20void Controller_XPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
21 std::size_t size) {
21 for (auto& xpad_entry : shared_memory.shared_memory_entries) { 22 for (auto& xpad_entry : shared_memory.shared_memory_entries) {
22 xpad_entry.header.timestamp = Core::Timing::GetTicks(); 23 xpad_entry.header.timestamp = core_timing.GetTicks();
23 xpad_entry.header.total_entry_count = 17; 24 xpad_entry.header.total_entry_count = 17;
24 25
25 if (!IsControllerActivated()) { 26 if (!IsControllerActivated()) {
diff --git a/src/core/hle/service/hid/controllers/xpad.h b/src/core/hle/service/hid/controllers/xpad.h
index ff836989f..2864e6617 100644
--- a/src/core/hle/service/hid/controllers/xpad.h
+++ b/src/core/hle/service/hid/controllers/xpad.h
@@ -22,7 +22,7 @@ public:
22 void OnRelease() override; 22 void OnRelease() override;
23 23
24 // When the controller is requesting an update for the shared memory 24 // When the controller is requesting an update for the shared memory
25 void OnUpdate(u8* data, std::size_t size) override; 25 void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
26 26
27 // Called when input devices should be loaded 27 // Called when input devices should be loaded
28 void OnLoadInputDevices() override; 28 void OnLoadInputDevices() override;
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 79c320d04..8a6de83a2 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -73,13 +73,15 @@ IAppletResource::IAppletResource() : ServiceFramework("IAppletResource") {
73 GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000); 73 GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000);
74 74
75 // Register update callbacks 75 // Register update callbacks
76 pad_update_event = Core::Timing::RegisterEvent( 76 auto& core_timing = Core::System::GetInstance().CoreTiming();
77 "HID::UpdatePadCallback", 77 pad_update_event =
78 [this](u64 userdata, int cycles_late) { UpdateControllers(userdata, cycles_late); }); 78 core_timing.RegisterEvent("HID::UpdatePadCallback", [this](u64 userdata, int cycles_late) {
79 UpdateControllers(userdata, cycles_late);
80 });
79 81
80 // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?) 82 // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?)
81 83
82 Core::Timing::ScheduleEvent(pad_update_ticks, pad_update_event); 84 core_timing.ScheduleEvent(pad_update_ticks, pad_update_event);
83 85
84 ReloadInputDevices(); 86 ReloadInputDevices();
85} 87}
@@ -93,7 +95,7 @@ void IAppletResource::DeactivateController(HidController controller) {
93} 95}
94 96
95IAppletResource ::~IAppletResource() { 97IAppletResource ::~IAppletResource() {
96 Core::Timing::UnscheduleEvent(pad_update_event, 0); 98 Core::System::GetInstance().CoreTiming().UnscheduleEvent(pad_update_event, 0);
97} 99}
98 100
99void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) { 101void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
@@ -105,15 +107,17 @@ void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
105} 107}
106 108
107void IAppletResource::UpdateControllers(u64 userdata, int cycles_late) { 109void IAppletResource::UpdateControllers(u64 userdata, int cycles_late) {
110 auto& core_timing = Core::System::GetInstance().CoreTiming();
111
108 const bool should_reload = Settings::values.is_device_reload_pending.exchange(false); 112 const bool should_reload = Settings::values.is_device_reload_pending.exchange(false);
109 for (const auto& controller : controllers) { 113 for (const auto& controller : controllers) {
110 if (should_reload) { 114 if (should_reload) {
111 controller->OnLoadInputDevices(); 115 controller->OnLoadInputDevices();
112 } 116 }
113 controller->OnUpdate(shared_mem->GetPointer(), SHARED_MEMORY_SIZE); 117 controller->OnUpdate(core_timing, shared_mem->GetPointer(), SHARED_MEMORY_SIZE);
114 } 118 }
115 119
116 Core::Timing::ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event); 120 core_timing.ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event);
117} 121}
118 122
119class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> { 123class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> {
diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp
index b427d4068..2c4625c99 100644
--- a/src/core/hle/service/hid/irs.cpp
+++ b/src/core/hle/service/hid/irs.cpp
@@ -98,7 +98,7 @@ void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) {
98 98
99 IPC::ResponseBuilder rb{ctx, 5}; 99 IPC::ResponseBuilder rb{ctx, 5};
100 rb.Push(RESULT_SUCCESS); 100 rb.Push(RESULT_SUCCESS);
101 rb.PushRaw<u64>(Core::Timing::GetTicks()); 101 rb.PushRaw<u64>(Core::System::GetInstance().CoreTiming().GetTicks());
102 rb.PushRaw<u32>(0); 102 rb.PushRaw<u32>(0);
103} 103}
104 104
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
index 88d80ba06..45812d238 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
@@ -5,6 +5,7 @@
5#include <cstring> 5#include <cstring>
6#include "common/assert.h" 6#include "common/assert.h"
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "core/core.h"
8#include "core/core_timing.h" 9#include "core/core_timing.h"
9#include "core/core_timing_util.h" 10#include "core/core_timing_util.h"
10#include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h" 11#include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h"
@@ -184,7 +185,7 @@ u32 nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& o
184 185
185 IoctlGetGpuTime params{}; 186 IoctlGetGpuTime params{};
186 std::memcpy(&params, input.data(), input.size()); 187 std::memcpy(&params, input.data(), input.size());
187 params.gpu_time = Core::Timing::cyclesToNs(Core::Timing::GetTicks()); 188 params.gpu_time = Core::Timing::cyclesToNs(Core::System::GetInstance().CoreTiming().GetTicks());
188 std::memcpy(output.data(), &params, output.size()); 189 std::memcpy(output.data(), &params, output.size());
189 return 0; 190 return 0;
190} 191}
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index ce1b59860..3babc3f7c 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -27,19 +27,19 @@ namespace Service::NVFlinger {
27constexpr std::size_t SCREEN_REFRESH_RATE = 60; 27constexpr std::size_t SCREEN_REFRESH_RATE = 60;
28constexpr u64 frame_ticks = static_cast<u64>(Core::Timing::BASE_CLOCK_RATE / SCREEN_REFRESH_RATE); 28constexpr u64 frame_ticks = static_cast<u64>(Core::Timing::BASE_CLOCK_RATE / SCREEN_REFRESH_RATE);
29 29
30NVFlinger::NVFlinger() { 30NVFlinger::NVFlinger(Core::Timing::CoreTiming& core_timing) : core_timing{core_timing} {
31 // Schedule the screen composition events 31 // Schedule the screen composition events
32 composition_event = 32 composition_event =
33 Core::Timing::RegisterEvent("ScreenComposition", [this](u64 userdata, int cycles_late) { 33 core_timing.RegisterEvent("ScreenComposition", [this](u64 userdata, int cycles_late) {
34 Compose(); 34 Compose();
35 Core::Timing::ScheduleEvent(frame_ticks - cycles_late, composition_event); 35 this->core_timing.ScheduleEvent(frame_ticks - cycles_late, composition_event);
36 }); 36 });
37 37
38 Core::Timing::ScheduleEvent(frame_ticks, composition_event); 38 core_timing.ScheduleEvent(frame_ticks, composition_event);
39} 39}
40 40
41NVFlinger::~NVFlinger() { 41NVFlinger::~NVFlinger() {
42 Core::Timing::UnscheduleEvent(composition_event, 0); 42 core_timing.UnscheduleEvent(composition_event, 0);
43} 43}
44 44
45void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) { 45void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
index 6d8bcbd30..437aa592d 100644
--- a/src/core/hle/service/nvflinger/nvflinger.h
+++ b/src/core/hle/service/nvflinger/nvflinger.h
@@ -15,8 +15,9 @@
15#include "core/hle/kernel/object.h" 15#include "core/hle/kernel/object.h"
16 16
17namespace Core::Timing { 17namespace Core::Timing {
18class CoreTiming;
18struct EventType; 19struct EventType;
19} 20} // namespace Core::Timing
20 21
21namespace Kernel { 22namespace Kernel {
22class ReadableEvent; 23class ReadableEvent;
@@ -52,7 +53,7 @@ struct Display {
52 53
53class NVFlinger final { 54class NVFlinger final {
54public: 55public:
55 NVFlinger(); 56 explicit NVFlinger(Core::Timing::CoreTiming& core_timing);
56 ~NVFlinger(); 57 ~NVFlinger();
57 58
58 /// Sets the NVDrv module instance to use to send buffers to the GPU. 59 /// Sets the NVDrv module instance to use to send buffers to the GPU.
@@ -117,6 +118,9 @@ private:
117 118
118 /// Event that handles screen composition. 119 /// Event that handles screen composition.
119 Core::Timing::EventType* composition_event; 120 Core::Timing::EventType* composition_event;
121
122 /// Core timing instance for registering/unregistering the composition event.
123 Core::Timing::CoreTiming& core_timing;
120}; 124};
121 125
122} // namespace Service::NVFlinger 126} // namespace Service::NVFlinger
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index d25b80ab0..117f87a45 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -194,10 +194,11 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co
194// Module interface 194// Module interface
195 195
196/// Initialize ServiceManager 196/// Initialize ServiceManager
197void Init(std::shared_ptr<SM::ServiceManager>& sm, FileSys::VfsFilesystem& vfs) { 197void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system,
198 FileSys::VfsFilesystem& vfs) {
198 // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it 199 // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it
199 // here and pass it into the respective InstallInterfaces functions. 200 // here and pass it into the respective InstallInterfaces functions.
200 auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(); 201 auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(system.CoreTiming());
201 202
202 SM::ServiceManager::InstallInterfaces(sm); 203 SM::ServiceManager::InstallInterfaces(sm);
203 204
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 029533628..830790269 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -14,6 +14,14 @@
14//////////////////////////////////////////////////////////////////////////////////////////////////// 14////////////////////////////////////////////////////////////////////////////////////////////////////
15// Namespace Service 15// Namespace Service
16 16
17namespace Core {
18class System;
19}
20
21namespace FileSys {
22class VfsFilesystem;
23}
24
17namespace Kernel { 25namespace Kernel {
18class ClientPort; 26class ClientPort;
19class ServerPort; 27class ServerPort;
@@ -21,10 +29,6 @@ class ServerSession;
21class HLERequestContext; 29class HLERequestContext;
22} // namespace Kernel 30} // namespace Kernel
23 31
24namespace FileSys {
25class VfsFilesystem;
26}
27
28namespace Service { 32namespace Service {
29 33
30namespace SM { 34namespace SM {
@@ -178,7 +182,8 @@ private:
178}; 182};
179 183
180/// Initialize ServiceManager 184/// Initialize ServiceManager
181void Init(std::shared_ptr<SM::ServiceManager>& sm, FileSys::VfsFilesystem& vfs); 185void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system,
186 FileSys::VfsFilesystem& vfs);
182 187
183/// Shutdown ServiceManager 188/// Shutdown ServiceManager
184void Shutdown(); 189void Shutdown();
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp
index efebd1b24..aa115935d 100644
--- a/src/core/hle/service/time/time.cpp
+++ b/src/core/hle/service/time/time.cpp
@@ -5,6 +5,7 @@
5#include <chrono> 5#include <chrono>
6#include <ctime> 6#include <ctime>
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "core/core.h"
8#include "core/core_timing.h" 9#include "core/core_timing.h"
9#include "core/core_timing_util.h" 10#include "core/core_timing_util.h"
10#include "core/hle/ipc_helpers.h" 11#include "core/hle/ipc_helpers.h"
@@ -106,8 +107,9 @@ private:
106 void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) { 107 void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) {
107 LOG_DEBUG(Service_Time, "called"); 108 LOG_DEBUG(Service_Time, "called");
108 109
110 const auto& core_timing = Core::System::GetInstance().CoreTiming();
109 const SteadyClockTimePoint steady_clock_time_point{ 111 const SteadyClockTimePoint steady_clock_time_point{
110 Core::Timing::cyclesToMs(Core::Timing::GetTicks()) / 1000}; 112 Core::Timing::cyclesToMs(core_timing.GetTicks()) / 1000};
111 IPC::ResponseBuilder rb{ctx, (sizeof(SteadyClockTimePoint) / 4) + 2}; 113 IPC::ResponseBuilder rb{ctx, (sizeof(SteadyClockTimePoint) / 4) + 2};
112 rb.Push(RESULT_SUCCESS); 114 rb.Push(RESULT_SUCCESS);
113 rb.PushRaw(steady_clock_time_point); 115 rb.PushRaw(steady_clock_time_point);
@@ -281,8 +283,9 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
281 return; 283 return;
282 } 284 }
283 285
286 const auto& core_timing = Core::System::GetInstance().CoreTiming();
284 const SteadyClockTimePoint steady_clock_time_point{ 287 const SteadyClockTimePoint steady_clock_time_point{
285 Core::Timing::cyclesToMs(Core::Timing::GetTicks()) / 1000, {}}; 288 Core::Timing::cyclesToMs(core_timing.GetTicks()) / 1000, {}};
286 289
287 CalendarTime calendar_time{}; 290 CalendarTime calendar_time{};
288 calendar_time.year = tm->tm_year + 1900; 291 calendar_time.year = tm->tm_year + 1900;
diff --git a/src/tests/core/core_timing.cpp b/src/tests/core/core_timing.cpp
index 77607a755..340d6a272 100644
--- a/src/tests/core/core_timing.cpp
+++ b/src/tests/core/core_timing.cpp
@@ -28,100 +28,103 @@ void CallbackTemplate(u64 userdata, s64 cycles_late) {
28 REQUIRE(lateness == cycles_late); 28 REQUIRE(lateness == cycles_late);
29} 29}
30 30
31class ScopeInit final { 31struct ScopeInit final {
32public:
33 ScopeInit() { 32 ScopeInit() {
34 Core::Timing::Init(); 33 core_timing.Initialize();
35 } 34 }
36 ~ScopeInit() { 35 ~ScopeInit() {
37 Core::Timing::Shutdown(); 36 core_timing.Shutdown();
38 } 37 }
38
39 Core::Timing::CoreTiming core_timing;
39}; 40};
40 41
41static void AdvanceAndCheck(u32 idx, int downcount, int expected_lateness = 0, 42static void AdvanceAndCheck(Core::Timing::CoreTiming& core_timing, u32 idx, int downcount,
42 int cpu_downcount = 0) { 43 int expected_lateness = 0, int cpu_downcount = 0) {
43 callbacks_ran_flags = 0; 44 callbacks_ran_flags = 0;
44 expected_callback = CB_IDS[idx]; 45 expected_callback = CB_IDS[idx];
45 lateness = expected_lateness; 46 lateness = expected_lateness;
46 47
47 // Pretend we executed X cycles of instructions. 48 // Pretend we executed X cycles of instructions.
48 Core::Timing::AddTicks(Core::Timing::GetDowncount() - cpu_downcount); 49 core_timing.AddTicks(core_timing.GetDowncount() - cpu_downcount);
49 Core::Timing::Advance(); 50 core_timing.Advance();
50 51
51 REQUIRE(decltype(callbacks_ran_flags)().set(idx) == callbacks_ran_flags); 52 REQUIRE(decltype(callbacks_ran_flags)().set(idx) == callbacks_ran_flags);
52 REQUIRE(downcount == Core::Timing::GetDowncount()); 53 REQUIRE(downcount == core_timing.GetDowncount());
53} 54}
54 55
55TEST_CASE("CoreTiming[BasicOrder]", "[core]") { 56TEST_CASE("CoreTiming[BasicOrder]", "[core]") {
56 ScopeInit guard; 57 ScopeInit guard;
58 auto& core_timing = guard.core_timing;
57 59
58 Core::Timing::EventType* cb_a = Core::Timing::RegisterEvent("callbackA", CallbackTemplate<0>); 60 Core::Timing::EventType* cb_a = core_timing.RegisterEvent("callbackA", CallbackTemplate<0>);
59 Core::Timing::EventType* cb_b = Core::Timing::RegisterEvent("callbackB", CallbackTemplate<1>); 61 Core::Timing::EventType* cb_b = core_timing.RegisterEvent("callbackB", CallbackTemplate<1>);
60 Core::Timing::EventType* cb_c = Core::Timing::RegisterEvent("callbackC", CallbackTemplate<2>); 62 Core::Timing::EventType* cb_c = core_timing.RegisterEvent("callbackC", CallbackTemplate<2>);
61 Core::Timing::EventType* cb_d = Core::Timing::RegisterEvent("callbackD", CallbackTemplate<3>); 63 Core::Timing::EventType* cb_d = core_timing.RegisterEvent("callbackD", CallbackTemplate<3>);
62 Core::Timing::EventType* cb_e = Core::Timing::RegisterEvent("callbackE", CallbackTemplate<4>); 64 Core::Timing::EventType* cb_e = core_timing.RegisterEvent("callbackE", CallbackTemplate<4>);
63 65
64 // Enter slice 0 66 // Enter slice 0
65 Core::Timing::Advance(); 67 core_timing.Advance();
66 68
67 // D -> B -> C -> A -> E 69 // D -> B -> C -> A -> E
68 Core::Timing::ScheduleEvent(1000, cb_a, CB_IDS[0]); 70 core_timing.ScheduleEvent(1000, cb_a, CB_IDS[0]);
69 REQUIRE(1000 == Core::Timing::GetDowncount()); 71 REQUIRE(1000 == core_timing.GetDowncount());
70 Core::Timing::ScheduleEvent(500, cb_b, CB_IDS[1]); 72 core_timing.ScheduleEvent(500, cb_b, CB_IDS[1]);
71 REQUIRE(500 == Core::Timing::GetDowncount()); 73 REQUIRE(500 == core_timing.GetDowncount());
72 Core::Timing::ScheduleEvent(800, cb_c, CB_IDS[2]); 74 core_timing.ScheduleEvent(800, cb_c, CB_IDS[2]);
73 REQUIRE(500 == Core::Timing::GetDowncount()); 75 REQUIRE(500 == core_timing.GetDowncount());
74 Core::Timing::ScheduleEvent(100, cb_d, CB_IDS[3]); 76 core_timing.ScheduleEvent(100, cb_d, CB_IDS[3]);
75 REQUIRE(100 == Core::Timing::GetDowncount()); 77 REQUIRE(100 == core_timing.GetDowncount());
76 Core::Timing::ScheduleEvent(1200, cb_e, CB_IDS[4]); 78 core_timing.ScheduleEvent(1200, cb_e, CB_IDS[4]);
77 REQUIRE(100 == Core::Timing::GetDowncount()); 79 REQUIRE(100 == core_timing.GetDowncount());
78 80
79 AdvanceAndCheck(3, 400); 81 AdvanceAndCheck(core_timing, 3, 400);
80 AdvanceAndCheck(1, 300); 82 AdvanceAndCheck(core_timing, 1, 300);
81 AdvanceAndCheck(2, 200); 83 AdvanceAndCheck(core_timing, 2, 200);
82 AdvanceAndCheck(0, 200); 84 AdvanceAndCheck(core_timing, 0, 200);
83 AdvanceAndCheck(4, MAX_SLICE_LENGTH); 85 AdvanceAndCheck(core_timing, 4, MAX_SLICE_LENGTH);
84} 86}
85 87
86TEST_CASE("CoreTiming[Threadsave]", "[core]") { 88TEST_CASE("CoreTiming[Threadsave]", "[core]") {
87 ScopeInit guard; 89 ScopeInit guard;
90 auto& core_timing = guard.core_timing;
88 91
89 Core::Timing::EventType* cb_a = Core::Timing::RegisterEvent("callbackA", CallbackTemplate<0>); 92 Core::Timing::EventType* cb_a = core_timing.RegisterEvent("callbackA", CallbackTemplate<0>);
90 Core::Timing::EventType* cb_b = Core::Timing::RegisterEvent("callbackB", CallbackTemplate<1>); 93 Core::Timing::EventType* cb_b = core_timing.RegisterEvent("callbackB", CallbackTemplate<1>);
91 Core::Timing::EventType* cb_c = Core::Timing::RegisterEvent("callbackC", CallbackTemplate<2>); 94 Core::Timing::EventType* cb_c = core_timing.RegisterEvent("callbackC", CallbackTemplate<2>);
92 Core::Timing::EventType* cb_d = Core::Timing::RegisterEvent("callbackD", CallbackTemplate<3>); 95 Core::Timing::EventType* cb_d = core_timing.RegisterEvent("callbackD", CallbackTemplate<3>);
93 Core::Timing::EventType* cb_e = Core::Timing::RegisterEvent("callbackE", CallbackTemplate<4>); 96 Core::Timing::EventType* cb_e = core_timing.RegisterEvent("callbackE", CallbackTemplate<4>);
94 97
95 // Enter slice 0 98 // Enter slice 0
96 Core::Timing::Advance(); 99 core_timing.Advance();
97 100
98 // D -> B -> C -> A -> E 101 // D -> B -> C -> A -> E
99 Core::Timing::ScheduleEventThreadsafe(1000, cb_a, CB_IDS[0]); 102 core_timing.ScheduleEventThreadsafe(1000, cb_a, CB_IDS[0]);
100 // Manually force since ScheduleEventThreadsafe doesn't call it 103 // Manually force since ScheduleEventThreadsafe doesn't call it
101 Core::Timing::ForceExceptionCheck(1000); 104 core_timing.ForceExceptionCheck(1000);
102 REQUIRE(1000 == Core::Timing::GetDowncount()); 105 REQUIRE(1000 == core_timing.GetDowncount());
103 Core::Timing::ScheduleEventThreadsafe(500, cb_b, CB_IDS[1]); 106 core_timing.ScheduleEventThreadsafe(500, cb_b, CB_IDS[1]);
104 // Manually force since ScheduleEventThreadsafe doesn't call it 107 // Manually force since ScheduleEventThreadsafe doesn't call it
105 Core::Timing::ForceExceptionCheck(500); 108 core_timing.ForceExceptionCheck(500);
106 REQUIRE(500 == Core::Timing::GetDowncount()); 109 REQUIRE(500 == core_timing.GetDowncount());
107 Core::Timing::ScheduleEventThreadsafe(800, cb_c, CB_IDS[2]); 110 core_timing.ScheduleEventThreadsafe(800, cb_c, CB_IDS[2]);
108 // Manually force since ScheduleEventThreadsafe doesn't call it 111 // Manually force since ScheduleEventThreadsafe doesn't call it
109 Core::Timing::ForceExceptionCheck(800); 112 core_timing.ForceExceptionCheck(800);
110 REQUIRE(500 == Core::Timing::GetDowncount()); 113 REQUIRE(500 == core_timing.GetDowncount());
111 Core::Timing::ScheduleEventThreadsafe(100, cb_d, CB_IDS[3]); 114 core_timing.ScheduleEventThreadsafe(100, cb_d, CB_IDS[3]);
112 // Manually force since ScheduleEventThreadsafe doesn't call it 115 // Manually force since ScheduleEventThreadsafe doesn't call it
113 Core::Timing::ForceExceptionCheck(100); 116 core_timing.ForceExceptionCheck(100);
114 REQUIRE(100 == Core::Timing::GetDowncount()); 117 REQUIRE(100 == core_timing.GetDowncount());
115 Core::Timing::ScheduleEventThreadsafe(1200, cb_e, CB_IDS[4]); 118 core_timing.ScheduleEventThreadsafe(1200, cb_e, CB_IDS[4]);
116 // Manually force since ScheduleEventThreadsafe doesn't call it 119 // Manually force since ScheduleEventThreadsafe doesn't call it
117 Core::Timing::ForceExceptionCheck(1200); 120 core_timing.ForceExceptionCheck(1200);
118 REQUIRE(100 == Core::Timing::GetDowncount()); 121 REQUIRE(100 == core_timing.GetDowncount());
119 122
120 AdvanceAndCheck(3, 400); 123 AdvanceAndCheck(core_timing, 3, 400);
121 AdvanceAndCheck(1, 300); 124 AdvanceAndCheck(core_timing, 1, 300);
122 AdvanceAndCheck(2, 200); 125 AdvanceAndCheck(core_timing, 2, 200);
123 AdvanceAndCheck(0, 200); 126 AdvanceAndCheck(core_timing, 0, 200);
124 AdvanceAndCheck(4, MAX_SLICE_LENGTH); 127 AdvanceAndCheck(core_timing, 4, MAX_SLICE_LENGTH);
125} 128}
126 129
127namespace SharedSlotTest { 130namespace SharedSlotTest {
@@ -142,59 +145,62 @@ TEST_CASE("CoreTiming[SharedSlot]", "[core]") {
142 using namespace SharedSlotTest; 145 using namespace SharedSlotTest;
143 146
144 ScopeInit guard; 147 ScopeInit guard;
148 auto& core_timing = guard.core_timing;
145 149
146 Core::Timing::EventType* cb_a = Core::Timing::RegisterEvent("callbackA", FifoCallback<0>); 150 Core::Timing::EventType* cb_a = core_timing.RegisterEvent("callbackA", FifoCallback<0>);
147 Core::Timing::EventType* cb_b = Core::Timing::RegisterEvent("callbackB", FifoCallback<1>); 151 Core::Timing::EventType* cb_b = core_timing.RegisterEvent("callbackB", FifoCallback<1>);
148 Core::Timing::EventType* cb_c = Core::Timing::RegisterEvent("callbackC", FifoCallback<2>); 152 Core::Timing::EventType* cb_c = core_timing.RegisterEvent("callbackC", FifoCallback<2>);
149 Core::Timing::EventType* cb_d = Core::Timing::RegisterEvent("callbackD", FifoCallback<3>); 153 Core::Timing::EventType* cb_d = core_timing.RegisterEvent("callbackD", FifoCallback<3>);
150 Core::Timing::EventType* cb_e = Core::Timing::RegisterEvent("callbackE", FifoCallback<4>); 154 Core::Timing::EventType* cb_e = core_timing.RegisterEvent("callbackE", FifoCallback<4>);
151 155
152 Core::Timing::ScheduleEvent(1000, cb_a, CB_IDS[0]); 156 core_timing.ScheduleEvent(1000, cb_a, CB_IDS[0]);
153 Core::Timing::ScheduleEvent(1000, cb_b, CB_IDS[1]); 157 core_timing.ScheduleEvent(1000, cb_b, CB_IDS[1]);
154 Core::Timing::ScheduleEvent(1000, cb_c, CB_IDS[2]); 158 core_timing.ScheduleEvent(1000, cb_c, CB_IDS[2]);
155 Core::Timing::ScheduleEvent(1000, cb_d, CB_IDS[3]); 159 core_timing.ScheduleEvent(1000, cb_d, CB_IDS[3]);
156 Core::Timing::ScheduleEvent(1000, cb_e, CB_IDS[4]); 160 core_timing.ScheduleEvent(1000, cb_e, CB_IDS[4]);
157 161
158 // Enter slice 0 162 // Enter slice 0
159 Core::Timing::Advance(); 163 core_timing.Advance();
160 REQUIRE(1000 == Core::Timing::GetDowncount()); 164 REQUIRE(1000 == core_timing.GetDowncount());
161 165
162 callbacks_ran_flags = 0; 166 callbacks_ran_flags = 0;
163 counter = 0; 167 counter = 0;
164 lateness = 0; 168 lateness = 0;
165 Core::Timing::AddTicks(Core::Timing::GetDowncount()); 169 core_timing.AddTicks(core_timing.GetDowncount());
166 Core::Timing::Advance(); 170 core_timing.Advance();
167 REQUIRE(MAX_SLICE_LENGTH == Core::Timing::GetDowncount()); 171 REQUIRE(MAX_SLICE_LENGTH == core_timing.GetDowncount());
168 REQUIRE(0x1FULL == callbacks_ran_flags.to_ullong()); 172 REQUIRE(0x1FULL == callbacks_ran_flags.to_ullong());
169} 173}
170 174
171TEST_CASE("Core::Timing[PredictableLateness]", "[core]") { 175TEST_CASE("Core::Timing[PredictableLateness]", "[core]") {
172 ScopeInit guard; 176 ScopeInit guard;
177 auto& core_timing = guard.core_timing;
173 178
174 Core::Timing::EventType* cb_a = Core::Timing::RegisterEvent("callbackA", CallbackTemplate<0>); 179 Core::Timing::EventType* cb_a = core_timing.RegisterEvent("callbackA", CallbackTemplate<0>);
175 Core::Timing::EventType* cb_b = Core::Timing::RegisterEvent("callbackB", CallbackTemplate<1>); 180 Core::Timing::EventType* cb_b = core_timing.RegisterEvent("callbackB", CallbackTemplate<1>);
176 181
177 // Enter slice 0 182 // Enter slice 0
178 Core::Timing::Advance(); 183 core_timing.Advance();
179 184
180 Core::Timing::ScheduleEvent(100, cb_a, CB_IDS[0]); 185 core_timing.ScheduleEvent(100, cb_a, CB_IDS[0]);
181 Core::Timing::ScheduleEvent(200, cb_b, CB_IDS[1]); 186 core_timing.ScheduleEvent(200, cb_b, CB_IDS[1]);
182 187
183 AdvanceAndCheck(0, 90, 10, -10); // (100 - 10) 188 AdvanceAndCheck(core_timing, 0, 90, 10, -10); // (100 - 10)
184 AdvanceAndCheck(1, MAX_SLICE_LENGTH, 50, -50); 189 AdvanceAndCheck(core_timing, 1, MAX_SLICE_LENGTH, 50, -50);
185} 190}
186 191
187namespace ChainSchedulingTest { 192namespace ChainSchedulingTest {
188static int reschedules = 0; 193static int reschedules = 0;
189 194
190static void RescheduleCallback(u64 userdata, s64 cycles_late) { 195static void RescheduleCallback(Core::Timing::CoreTiming& core_timing, u64 userdata,
196 s64 cycles_late) {
191 --reschedules; 197 --reschedules;
192 REQUIRE(reschedules >= 0); 198 REQUIRE(reschedules >= 0);
193 REQUIRE(lateness == cycles_late); 199 REQUIRE(lateness == cycles_late);
194 200
195 if (reschedules > 0) { 201 if (reschedules > 0) {
196 Core::Timing::ScheduleEvent(1000, reinterpret_cast<Core::Timing::EventType*>(userdata), 202 core_timing.ScheduleEvent(1000, reinterpret_cast<Core::Timing::EventType*>(userdata),
197 userdata); 203 userdata);
198 } 204 }
199} 205}
200} // namespace ChainSchedulingTest 206} // namespace ChainSchedulingTest
@@ -203,36 +209,39 @@ TEST_CASE("CoreTiming[ChainScheduling]", "[core]") {
203 using namespace ChainSchedulingTest; 209 using namespace ChainSchedulingTest;
204 210
205 ScopeInit guard; 211 ScopeInit guard;
212 auto& core_timing = guard.core_timing;
206 213
207 Core::Timing::EventType* cb_a = Core::Timing::RegisterEvent("callbackA", CallbackTemplate<0>); 214 Core::Timing::EventType* cb_a = core_timing.RegisterEvent("callbackA", CallbackTemplate<0>);
208 Core::Timing::EventType* cb_b = Core::Timing::RegisterEvent("callbackB", CallbackTemplate<1>); 215 Core::Timing::EventType* cb_b = core_timing.RegisterEvent("callbackB", CallbackTemplate<1>);
209 Core::Timing::EventType* cb_c = Core::Timing::RegisterEvent("callbackC", CallbackTemplate<2>); 216 Core::Timing::EventType* cb_c = core_timing.RegisterEvent("callbackC", CallbackTemplate<2>);
210 Core::Timing::EventType* cb_rs = 217 Core::Timing::EventType* cb_rs = core_timing.RegisterEvent(
211 Core::Timing::RegisterEvent("callbackReschedule", RescheduleCallback); 218 "callbackReschedule", [&core_timing](u64 userdata, s64 cycles_late) {
219 RescheduleCallback(core_timing, userdata, cycles_late);
220 });
212 221
213 // Enter slice 0 222 // Enter slice 0
214 Core::Timing::Advance(); 223 core_timing.Advance();
215 224
216 Core::Timing::ScheduleEvent(800, cb_a, CB_IDS[0]); 225 core_timing.ScheduleEvent(800, cb_a, CB_IDS[0]);
217 Core::Timing::ScheduleEvent(1000, cb_b, CB_IDS[1]); 226 core_timing.ScheduleEvent(1000, cb_b, CB_IDS[1]);
218 Core::Timing::ScheduleEvent(2200, cb_c, CB_IDS[2]); 227 core_timing.ScheduleEvent(2200, cb_c, CB_IDS[2]);
219 Core::Timing::ScheduleEvent(1000, cb_rs, reinterpret_cast<u64>(cb_rs)); 228 core_timing.ScheduleEvent(1000, cb_rs, reinterpret_cast<u64>(cb_rs));
220 REQUIRE(800 == Core::Timing::GetDowncount()); 229 REQUIRE(800 == core_timing.GetDowncount());
221 230
222 reschedules = 3; 231 reschedules = 3;
223 AdvanceAndCheck(0, 200); // cb_a 232 AdvanceAndCheck(core_timing, 0, 200); // cb_a
224 AdvanceAndCheck(1, 1000); // cb_b, cb_rs 233 AdvanceAndCheck(core_timing, 1, 1000); // cb_b, cb_rs
225 REQUIRE(2 == reschedules); 234 REQUIRE(2 == reschedules);
226 235
227 Core::Timing::AddTicks(Core::Timing::GetDowncount()); 236 core_timing.AddTicks(core_timing.GetDowncount());
228 Core::Timing::Advance(); // cb_rs 237 core_timing.Advance(); // cb_rs
229 REQUIRE(1 == reschedules); 238 REQUIRE(1 == reschedules);
230 REQUIRE(200 == Core::Timing::GetDowncount()); 239 REQUIRE(200 == core_timing.GetDowncount());
231 240
232 AdvanceAndCheck(2, 800); // cb_c 241 AdvanceAndCheck(core_timing, 2, 800); // cb_c
233 242
234 Core::Timing::AddTicks(Core::Timing::GetDowncount()); 243 core_timing.AddTicks(core_timing.GetDowncount());
235 Core::Timing::Advance(); // cb_rs 244 core_timing.Advance(); // cb_rs
236 REQUIRE(0 == reschedules); 245 REQUIRE(0 == reschedules);
237 REQUIRE(MAX_SLICE_LENGTH == Core::Timing::GetDowncount()); 246 REQUIRE(MAX_SLICE_LENGTH == core_timing.GetDowncount());
238} 247}
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 19b6b14b2..86ede5faa 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -317,7 +317,7 @@ void Maxwell3D::ProcessQueryGet() {
317 LongQueryResult query_result{}; 317 LongQueryResult query_result{};
318 query_result.value = result; 318 query_result.value = result;
319 // TODO(Subv): Generate a real GPU timestamp and write it here instead of CoreTiming 319 // TODO(Subv): Generate a real GPU timestamp and write it here instead of CoreTiming
320 query_result.timestamp = Core::Timing::GetTicks(); 320 query_result.timestamp = Core::System::GetInstance().CoreTiming().GetTicks();
321 Memory::WriteBlock(*address, &query_result, sizeof(query_result)); 321 Memory::WriteBlock(*address, &query_result, sizeof(query_result));
322 } 322 }
323 dirty_flags.OnMemoryWrite(); 323 dirty_flags.OnMemoryWrite();
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index 3d00c308b..b86265dfe 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -3,6 +3,7 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/assert.h" 5#include "common/assert.h"
6#include "core/core.h"
6#include "core/core_timing.h" 7#include "core/core_timing.h"
7#include "core/memory.h" 8#include "core/memory.h"
8#include "video_core/engines/fermi_2d.h" 9#include "video_core/engines/fermi_2d.h"
@@ -283,7 +284,7 @@ void GPU::ProcessSemaphoreTriggerMethod() {
283 block.sequence = regs.semaphore_sequence; 284 block.sequence = regs.semaphore_sequence;
284 // TODO(Kmather73): Generate a real GPU timestamp and write it here instead of 285 // TODO(Kmather73): Generate a real GPU timestamp and write it here instead of
285 // CoreTiming 286 // CoreTiming
286 block.timestamp = Core::Timing::GetTicks(); 287 block.timestamp = Core::System::GetInstance().CoreTiming().GetTicks();
287 Memory::WriteBlock(*address, &block, sizeof(block)); 288 Memory::WriteBlock(*address, &block, sizeof(block));
288 } else { 289 } else {
289 const auto address = 290 const auto address =
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index cca2ed708..d40666ac6 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -137,7 +137,7 @@ void RendererOpenGL::SwapBuffers(
137 137
138 render_window.PollEvents(); 138 render_window.PollEvents();
139 139
140 system.FrameLimiter().DoFrameLimiting(Core::Timing::GetGlobalTimeUs()); 140 system.FrameLimiter().DoFrameLimiting(system.CoreTiming().GetGlobalTimeUs());
141 system.GetPerfStats().BeginSystemFrame(); 141 system.GetPerfStats().BeginSystemFrame();
142 142
143 // Restore the rasterizer state 143 // Restore the rasterizer state