diff options
| author | 2019-02-14 12:42:58 -0500 | |
|---|---|---|
| committer | 2019-02-15 21:50:25 -0500 | |
| commit | bd983414f643b734a1f8bebe3183723733344f72 (patch) | |
| tree | bda0421458439e25cba9d772a6a79b56e473d72e | |
| parent | Merge pull request #2113 from ReinUsesLisp/vulkan-base (diff) | |
| download | yuzu-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.
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 | ||
| 29 | StreamPtr AudioOut::OpenStream(u32 sample_rate, u32 num_channels, std::string&& name, | 29 | StreamPtr 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 | ||
| 16 | namespace Core::Timing { | ||
| 17 | class CoreTiming; | ||
| 18 | } | ||
| 19 | |||
| 16 | namespace AudioCore { | 20 | namespace AudioCore { |
| 17 | 21 | ||
| 18 | /** | 22 | /** |
| @@ -21,8 +25,8 @@ namespace AudioCore { | |||
| 21 | class AudioOut { | 25 | class AudioOut { |
| 22 | public: | 26 | public: |
| 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 | }; |
| 74 | AudioRenderer::AudioRenderer(AudioRendererParameter params, | 75 | AudioRenderer::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 | ||
| 17 | namespace Core::Timing { | ||
| 18 | class CoreTiming; | ||
| 19 | } | ||
| 20 | |||
| 17 | namespace Kernel { | 21 | namespace Kernel { |
| 18 | class WritableEvent; | 22 | class WritableEvent; |
| 19 | } | 23 | } |
| @@ -208,7 +212,7 @@ static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has wrong size | |||
| 208 | 212 | ||
| 209 | class AudioRenderer { | 213 | class AudioRenderer { |
| 210 | public: | 214 | public: |
| 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 | ||
| 35 | Stream::Stream(u32 sample_rate, Format format, ReleaseCallback&& release_callback, | 35 | Stream::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 | ||
| 106 | void Stream::ReleaseActiveBuffer() { | 105 | void 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 | ||
| 16 | namespace Core::Timing { | 16 | namespace Core::Timing { |
| 17 | class CoreTiming; | ||
| 17 | struct EventType; | 18 | struct EventType; |
| 18 | } | 19 | } // namespace Core::Timing |
| 19 | 20 | ||
| 20 | namespace AudioCore { | 21 | namespace 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 | ||
| 175 | ARM_Dynarmic::ARM_Dynarmic(ExclusiveMonitor& exclusive_monitor, std::size_t core_index) | 175 | ARM_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 { | |||
| 16 | struct PageTable; | 16 | struct PageTable; |
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | namespace Core::Timing { | ||
| 20 | class CoreTiming; | ||
| 21 | } | ||
| 22 | |||
| 19 | namespace Core { | 23 | namespace Core { |
| 20 | 24 | ||
| 21 | class ARM_Dynarmic_Callbacks; | 25 | class ARM_Dynarmic_Callbacks; |
| @@ -23,7 +27,8 @@ class DynarmicExclusiveMonitor; | |||
| 23 | 27 | ||
| 24 | class ARM_Dynarmic final : public ARM_Interface { | 28 | class ARM_Dynarmic final : public ARM_Interface { |
| 25 | public: | 29 | public: |
| 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 | ||
| 75 | ARM_Unicorn::ARM_Unicorn() { | 75 | ARM_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)); | |||
| 190 | void ARM_Unicorn::ExecuteInstructions(int num_instructions) { | 190 | void 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 | ||
| 12 | namespace Core::Timing { | ||
| 13 | class CoreTiming; | ||
| 14 | } | ||
| 15 | |||
| 12 | namespace Core { | 16 | namespace Core { |
| 13 | 17 | ||
| 14 | class ARM_Unicorn final : public ARM_Interface { | 18 | class ARM_Unicorn final : public ARM_Interface { |
| 15 | public: | 19 | public: |
| 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 | ||
| 44 | private: | 49 | private: |
| 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 | ||
| 400 | Timing::CoreTiming& System::CoreTiming() { | ||
| 401 | return impl->core_timing; | ||
| 402 | } | ||
| 403 | |||
| 404 | const Timing::CoreTiming& System::CoreTiming() const { | ||
| 405 | return impl->core_timing; | ||
| 406 | } | ||
| 407 | |||
| 399 | Core::PerfStats& System::GetPerfStats() { | 408 | Core::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 { | |||
| 47 | class RendererBase; | 47 | class RendererBase; |
| 48 | } // namespace VideoCore | 48 | } // namespace VideoCore |
| 49 | 49 | ||
| 50 | namespace Core::Timing { | ||
| 51 | class CoreTiming; | ||
| 52 | } | ||
| 53 | |||
| 50 | namespace Core { | 54 | namespace Core { |
| 51 | 55 | ||
| 52 | class ARM_Interface; | 56 | class 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 | ||
| 52 | Cpu::Cpu(ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_barrier, std::size_t core_index) | 52 | Cpu::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 { | |||
| 15 | class Scheduler; | 15 | class Scheduler; |
| 16 | } | 16 | } |
| 17 | 17 | ||
| 18 | namespace Core::Timing { | ||
| 19 | class CoreTiming; | ||
| 20 | } | ||
| 21 | |||
| 18 | namespace Core { | 22 | namespace Core { |
| 19 | 23 | ||
| 20 | class ARM_Interface; | 24 | class ARM_Interface; |
| @@ -41,7 +45,8 @@ private: | |||
| 41 | 45 | ||
| 42 | class Cpu { | 46 | class Cpu { |
| 43 | public: | 47 | public: |
| 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 | ||
| 18 | namespace Core::Timing { | 16 | namespace Core::Timing { |
| 19 | 17 | ||
| 20 | static s64 global_timer; | 18 | constexpr int MAX_SLICE_LENGTH = 20000; |
| 21 | static int slice_length; | ||
| 22 | static int downcount; | ||
| 23 | |||
| 24 | struct EventType { | ||
| 25 | TimedCallback callback; | ||
| 26 | const std::string* name; | ||
| 27 | }; | ||
| 28 | 19 | ||
| 29 | struct Event { | 20 | struct 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 | ||
| 37 | static 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 | |||
| 41 | static 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. | ||
| 47 | static 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); |
| 53 | static std::vector<Event> event_queue; | 30 | } |
| 54 | static 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 | ||
| 57 | static Common::MPSCQueue<Event> ts_queue; | ||
| 58 | |||
| 59 | // the queue for unscheduling the events from other threads threadsafe | ||
| 60 | static Common::MPSCQueue<std::pair<const EventType*, u64>> unschedule_queue; | ||
| 61 | |||
| 62 | constexpr int MAX_SLICE_LENGTH = 20000; | ||
| 63 | |||
| 64 | static 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. | ||
| 69 | static bool is_global_timer_sane; | ||
| 70 | |||
| 71 | static EventType* ev_lost = nullptr; | ||
| 72 | |||
| 73 | EventType* 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 | ||
| 87 | void UnregisterAllEvents() { | 37 | CoreTiming::CoreTiming() = default; |
| 88 | ASSERT_MSG(event_queue.empty(), "Cannot unregister events with events pending"); | 38 | CoreTiming::~CoreTiming() = default; |
| 89 | event_types.clear(); | ||
| 90 | } | ||
| 91 | 39 | ||
| 92 | void Init() { | 40 | void 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 | ||
| 110 | void Shutdown() { | 58 | void 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 | 64 | EventType* 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. |
| 118 | u64 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 | |||
| 126 | void AddTicks(u64 ticks) { | ||
| 127 | downcount -= static_cast<int>(ticks); | ||
| 128 | } | ||
| 129 | 71 | ||
| 130 | u64 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 | ||
| 134 | void ClearPendingEvents() { | 78 | void 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 | ||
| 138 | void ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 userdata) { | 83 | void 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 | ||
| 148 | void ScheduleEventThreadsafe(s64 cycles_into_future, const EventType* event_type, u64 userdata) { | 96 | void 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 | ||
| 152 | void UnscheduleEvent(const EventType* event_type, u64 userdata) { | 101 | void 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 | ||
| 164 | void UnscheduleEventThreadsafe(const EventType* event_type, u64 userdata) { | 113 | void 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 | ||
| 168 | void RemoveEvent(const EventType* event_type) { | 117 | u64 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 | |||
| 125 | u64 CoreTiming::GetIdleTicks() const { | ||
| 126 | return static_cast<u64>(idled_cycles); | ||
| 127 | } | ||
| 128 | |||
| 129 | void CoreTiming::AddTicks(u64 ticks) { | ||
| 130 | downcount -= static_cast<int>(ticks); | ||
| 131 | } | ||
| 132 | |||
| 133 | void CoreTiming::ClearPendingEvents() { | ||
| 134 | event_queue.clear(); | ||
| 135 | } | ||
| 136 | |||
| 137 | void 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 | ||
| 179 | void RemoveNormalAndThreadsafeEvent(const EventType* event_type) { | 148 | void CoreTiming::RemoveNormalAndThreadsafeEvent(const EventType* event_type) { |
| 180 | MoveEvents(); | 149 | MoveEvents(); |
| 181 | RemoveEvent(event_type); | 150 | RemoveEvent(event_type); |
| 182 | } | 151 | } |
| 183 | 152 | ||
| 184 | void ForceExceptionCheck(s64 cycles) { | 153 | void 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 | ||
| 194 | void MoveEvents() { | 165 | void 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 | ||
| 202 | void Advance() { | 173 | void 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 | ||
| 232 | void Idle() { | 203 | void CoreTiming::Idle() { |
| 233 | idled_cycles += downcount; | 204 | idled_cycles += downcount; |
| 234 | downcount = 0; | 205 | downcount = 0; |
| 235 | } | 206 | } |
| 236 | 207 | ||
| 237 | std::chrono::microseconds GetGlobalTimeUs() { | 208 | std::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 | ||
| 241 | int GetDowncount() { | 212 | int 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 | ||
| 25 | namespace Core::Timing { | 15 | namespace Core::Timing { |
| 26 | 16 | ||
| 27 | struct EventType; | 17 | /// A callback that may be scheduled for a particular core timing event. |
| 28 | |||
| 29 | using TimedCallback = std::function<void(u64 userdata, int cycles_late)>; | 18 | using 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 | 21 | struct 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; |
| 35 | void Init(); | 24 | /// A pointer to the name of the event. |
| 36 | void 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 | */ | ||
| 42 | u64 GetTicks(); | ||
| 43 | u64 GetIdleTicks(); | ||
| 44 | void AddTicks(u64 ticks); | ||
| 45 | |||
| 46 | /** | ||
| 47 | * Returns the event_type identifier. if name is not unique, it will assert. | ||
| 48 | */ | ||
| 49 | EventType* RegisterEvent(const std::string& name, TimedCallback callback); | ||
| 50 | void 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 | */ | ||
| 57 | void 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. |
| 65 | void 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. | |
| 67 | void UnscheduleEvent(const EventType* event_type, u64 userdata); | 36 | * So to schedule a new event on a regular basis: |
| 68 | void 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. | ||
| 71 | void RemoveEvent(const EventType* event_type); | ||
| 72 | void 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 | */ |
| 80 | void Advance(); | 40 | class CoreTiming { |
| 81 | void MoveEvents(); | 41 | public: |
| 82 | 42 | CoreTiming(); | |
| 83 | /// Pretend that the main CPU has executed enough cycles to reach the next event. | 43 | ~CoreTiming(); |
| 84 | void Idle(); | 44 | |
| 85 | 45 | CoreTiming(const CoreTiming&) = delete; | |
| 86 | /// Clear all pending events. This should ONLY be done on exit. | 46 | CoreTiming(CoreTiming&&) = delete; |
| 87 | void ClearPendingEvents(); | 47 | |
| 88 | 48 | CoreTiming& operator=(const CoreTiming&) = delete; | |
| 89 | void ForceExceptionCheck(s64 cycles); | 49 | CoreTiming& operator=(CoreTiming&&) = delete; |
| 90 | 50 | ||
| 91 | std::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. | |
| 93 | int 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 | |||
| 118 | private: | ||
| 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 | ||
| 88 | struct KernelCore::Impl { | 88 | struct 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 | ||
| 155 | void KernelCore::Initialize() { | 155 | void KernelCore::Initialize(Core::Timing::CoreTiming& core_timing) { |
| 156 | impl->Initialize(*this); | 156 | impl->Initialize(*this, core_timing); |
| 157 | } | 157 | } |
| 158 | 158 | ||
| 159 | void KernelCore::Shutdown() { | 159 | void 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> | |||
| 12 | class ResultVal; | 12 | class ResultVal; |
| 13 | 13 | ||
| 14 | namespace Core::Timing { | 14 | namespace Core::Timing { |
| 15 | class CoreTiming; | ||
| 15 | struct EventType; | 16 | struct EventType; |
| 16 | } | 17 | } // namespace Core::Timing |
| 17 | 18 | ||
| 18 | namespace Kernel { | 19 | namespace 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 | ||
| 112 | void Scheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) { | 112 | void 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 | |||
| 1546 | static u64 GetSystemTick() { | 1547 | static 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 | ||
| 44 | void Thread::Stop() { | 44 | void 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 | ||
| 92 | void Thread::CancelWakeupTimer() { | 94 | void 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 | ||
| 97 | static std::optional<s32> GetNextProcessorId(u64 mask) { | 99 | static 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 | ||
| 51 | private: | 52 | private: |
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 | ||
| 10 | namespace Core::Timing { | ||
| 11 | class CoreTiming; | ||
| 12 | } | ||
| 13 | |||
| 10 | namespace Service::HID { | 14 | namespace Service::HID { |
| 11 | class ControllerBase { | 15 | class ControllerBase { |
| 12 | public: | 16 | public: |
| @@ -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 | ||
| 22 | void Controller_DebugPad::OnRelease() {} | 22 | void Controller_DebugPad::OnRelease() {} |
| 23 | 23 | ||
| 24 | void Controller_DebugPad::OnUpdate(u8* data, std::size_t size) { | 24 | void 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 | ||
| 18 | void Controller_Gesture::OnRelease() {} | 18 | void Controller_Gesture::OnRelease() {} |
| 19 | 19 | ||
| 20 | void Controller_Gesture::OnUpdate(u8* data, std::size_t size) { | 20 | void 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 | ||
| 20 | void Controller_Keyboard::OnRelease() {} | 20 | void Controller_Keyboard::OnRelease() {} |
| 21 | 21 | ||
| 22 | void Controller_Keyboard::OnUpdate(u8* data, std::size_t size) { | 22 | void 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; | |||
| 17 | void Controller_Mouse::OnInit() {} | 17 | void Controller_Mouse::OnInit() {} |
| 18 | void Controller_Mouse::OnRelease() {} | 18 | void Controller_Mouse::OnRelease() {} |
| 19 | 19 | ||
| 20 | void Controller_Mouse::OnUpdate(u8* data, std::size_t size) { | 20 | void 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 | ||
| 291 | void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) { | 291 | void 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 | ||
| 17 | void Controller_Stubbed::OnRelease() {} | 17 | void Controller_Stubbed::OnRelease() {} |
| 18 | 18 | ||
| 19 | void Controller_Stubbed::OnUpdate(u8* data, std::size_t size) { | 19 | void 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 | ||
| 21 | void Controller_Touchscreen::OnRelease() {} | 21 | void Controller_Touchscreen::OnRelease() {} |
| 22 | 22 | ||
| 23 | void Controller_Touchscreen::OnUpdate(u8* data, std::size_t size) { | 23 | void 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 | ||
| 18 | void Controller_XPad::OnRelease() {} | 18 | void Controller_XPad::OnRelease() {} |
| 19 | 19 | ||
| 20 | void Controller_XPad::OnUpdate(u8* data, std::size_t size) { | 20 | void 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 | ||
| 95 | IAppletResource ::~IAppletResource() { | 97 | IAppletResource ::~IAppletResource() { |
| 96 | Core::Timing::UnscheduleEvent(pad_update_event, 0); | 98 | Core::System::GetInstance().CoreTiming().UnscheduleEvent(pad_update_event, 0); |
| 97 | } | 99 | } |
| 98 | 100 | ||
| 99 | void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) { | 101 | void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) { |
| @@ -105,15 +107,17 @@ void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) { | |||
| 105 | } | 107 | } |
| 106 | 108 | ||
| 107 | void IAppletResource::UpdateControllers(u64 userdata, int cycles_late) { | 109 | void 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 | ||
| 119 | class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> { | 123 | class 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(¶ms, input.data(), input.size()); | 187 | std::memcpy(¶ms, 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(), ¶ms, output.size()); | 189 | std::memcpy(output.data(), ¶ms, 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 { | |||
| 27 | constexpr std::size_t SCREEN_REFRESH_RATE = 60; | 27 | constexpr std::size_t SCREEN_REFRESH_RATE = 60; |
| 28 | constexpr u64 frame_ticks = static_cast<u64>(Core::Timing::BASE_CLOCK_RATE / SCREEN_REFRESH_RATE); | 28 | constexpr u64 frame_ticks = static_cast<u64>(Core::Timing::BASE_CLOCK_RATE / SCREEN_REFRESH_RATE); |
| 29 | 29 | ||
| 30 | NVFlinger::NVFlinger() { | 30 | NVFlinger::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 | ||
| 41 | NVFlinger::~NVFlinger() { | 41 | NVFlinger::~NVFlinger() { |
| 42 | Core::Timing::UnscheduleEvent(composition_event, 0); | 42 | core_timing.UnscheduleEvent(composition_event, 0); |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) { | 45 | void 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 | ||
| 17 | namespace Core::Timing { | 17 | namespace Core::Timing { |
| 18 | class CoreTiming; | ||
| 18 | struct EventType; | 19 | struct EventType; |
| 19 | } | 20 | } // namespace Core::Timing |
| 20 | 21 | ||
| 21 | namespace Kernel { | 22 | namespace Kernel { |
| 22 | class ReadableEvent; | 23 | class ReadableEvent; |
| @@ -52,7 +53,7 @@ struct Display { | |||
| 52 | 53 | ||
| 53 | class NVFlinger final { | 54 | class NVFlinger final { |
| 54 | public: | 55 | public: |
| 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 |
| 197 | void Init(std::shared_ptr<SM::ServiceManager>& sm, FileSys::VfsFilesystem& vfs) { | 197 | void 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 | ||
| 17 | namespace Core { | ||
| 18 | class System; | ||
| 19 | } | ||
| 20 | |||
| 21 | namespace FileSys { | ||
| 22 | class VfsFilesystem; | ||
| 23 | } | ||
| 24 | |||
| 17 | namespace Kernel { | 25 | namespace Kernel { |
| 18 | class ClientPort; | 26 | class ClientPort; |
| 19 | class ServerPort; | 27 | class ServerPort; |
| @@ -21,10 +29,6 @@ class ServerSession; | |||
| 21 | class HLERequestContext; | 29 | class HLERequestContext; |
| 22 | } // namespace Kernel | 30 | } // namespace Kernel |
| 23 | 31 | ||
| 24 | namespace FileSys { | ||
| 25 | class VfsFilesystem; | ||
| 26 | } | ||
| 27 | |||
| 28 | namespace Service { | 32 | namespace Service { |
| 29 | 33 | ||
| 30 | namespace SM { | 34 | namespace SM { |
| @@ -178,7 +182,8 @@ private: | |||
| 178 | }; | 182 | }; |
| 179 | 183 | ||
| 180 | /// Initialize ServiceManager | 184 | /// Initialize ServiceManager |
| 181 | void Init(std::shared_ptr<SM::ServiceManager>& sm, FileSys::VfsFilesystem& vfs); | 185 | void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system, |
| 186 | FileSys::VfsFilesystem& vfs); | ||
| 182 | 187 | ||
| 183 | /// Shutdown ServiceManager | 188 | /// Shutdown ServiceManager |
| 184 | void Shutdown(); | 189 | void 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 | ||
| 31 | class ScopeInit final { | 31 | struct ScopeInit final { |
| 32 | public: | ||
| 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 | ||
| 41 | static void AdvanceAndCheck(u32 idx, int downcount, int expected_lateness = 0, | 42 | static 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 | ||
| 55 | TEST_CASE("CoreTiming[BasicOrder]", "[core]") { | 56 | TEST_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 | ||
| 86 | TEST_CASE("CoreTiming[Threadsave]", "[core]") { | 88 | TEST_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 | ||
| 127 | namespace SharedSlotTest { | 130 | namespace 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 | ||
| 171 | TEST_CASE("Core::Timing[PredictableLateness]", "[core]") { | 175 | TEST_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 | ||
| 187 | namespace ChainSchedulingTest { | 192 | namespace ChainSchedulingTest { |
| 188 | static int reschedules = 0; | 193 | static int reschedules = 0; |
| 189 | 194 | ||
| 190 | static void RescheduleCallback(u64 userdata, s64 cycles_late) { | 195 | static 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 |