diff options
| author | 2022-07-10 06:59:40 +0100 | |
|---|---|---|
| committer | 2022-07-10 06:59:40 +0100 | |
| commit | 240650f6a6336df8d3eb11b410cdcd332d8ad562 (patch) | |
| tree | 16ae249e6160a22f88bd2238d43b23079c4afb44 | |
| parent | Merge pull request #8531 from FernandoS27/core-timing-fix-reg (diff) | |
| download | yuzu-240650f6a6336df8d3eb11b410cdcd332d8ad562.tar.gz yuzu-240650f6a6336df8d3eb11b410cdcd332d8ad562.tar.xz yuzu-240650f6a6336df8d3eb11b410cdcd332d8ad562.zip | |
Rework CoreTiming
Diffstat (limited to '')
| -rw-r--r-- | src/audio_core/audio_renderer.cpp | 10 | ||||
| -rw-r--r-- | src/audio_core/stream.cpp | 5 | ||||
| -rw-r--r-- | src/core/core_timing.cpp | 75 | ||||
| -rw-r--r-- | src/core/core_timing.h | 23 | ||||
| -rw-r--r-- | src/core/hardware_interrupt_manager.cpp | 5 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 10 | ||||
| -rw-r--r-- | src/core/hle/kernel/time_manager.cpp | 20 | ||||
| -rw-r--r-- | src/core/hle/service/hid/hid.cpp | 42 | ||||
| -rw-r--r-- | src/core/hle/service/hid/hidbus.cpp | 16 | ||||
| -rw-r--r-- | src/core/hle/service/nvflinger/nvflinger.cpp | 13 | ||||
| -rw-r--r-- | src/core/memory/cheat_engine.cpp | 8 | ||||
| -rw-r--r-- | src/core/tools/freezer.cpp | 4 | ||||
| -rw-r--r-- | src/tests/core/core_timing.cpp | 5 |
13 files changed, 154 insertions, 82 deletions
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp index 2ee0a96ed..9191ca093 100644 --- a/src/audio_core/audio_renderer.cpp +++ b/src/audio_core/audio_renderer.cpp | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include <limits> | 4 | #include <limits> |
| 5 | #include <optional> | ||
| 5 | #include <vector> | 6 | #include <vector> |
| 6 | 7 | ||
| 7 | #include "audio_core/audio_out.h" | 8 | #include "audio_core/audio_out.h" |
| @@ -88,9 +89,12 @@ AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing_, Core::Memor | |||
| 88 | stream = audio_out->OpenStream( | 89 | stream = audio_out->OpenStream( |
| 89 | core_timing, params.sample_rate, AudioCommon::STREAM_NUM_CHANNELS, | 90 | core_timing, params.sample_rate, AudioCommon::STREAM_NUM_CHANNELS, |
| 90 | fmt::format("AudioRenderer-Instance{}", instance_number), std::move(release_callback)); | 91 | fmt::format("AudioRenderer-Instance{}", instance_number), std::move(release_callback)); |
| 91 | process_event = Core::Timing::CreateEvent( | 92 | process_event = |
| 92 | fmt::format("AudioRenderer-Instance{}-Process", instance_number), | 93 | Core::Timing::CreateEvent(fmt::format("AudioRenderer-Instance{}-Process", instance_number), |
| 93 | [this](std::uintptr_t, std::chrono::nanoseconds) { ReleaseAndQueueBuffers(); }); | 94 | [this](std::uintptr_t, s64, std::chrono::nanoseconds) { |
| 95 | ReleaseAndQueueBuffers(); | ||
| 96 | return std::nullopt; | ||
| 97 | }); | ||
| 94 | for (s32 i = 0; i < NUM_BUFFERS; ++i) { | 98 | for (s32 i = 0; i < NUM_BUFFERS; ++i) { |
| 95 | QueueMixedBuffer(i); | 99 | QueueMixedBuffer(i); |
| 96 | } | 100 | } |
diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp index f8034b04b..cf3d94c53 100644 --- a/src/audio_core/stream.cpp +++ b/src/audio_core/stream.cpp | |||
| @@ -34,9 +34,10 @@ Stream::Stream(Core::Timing::CoreTiming& core_timing_, u32 sample_rate_, Format | |||
| 34 | ReleaseCallback&& release_callback_, SinkStream& sink_stream_, std::string&& name_) | 34 | ReleaseCallback&& release_callback_, SinkStream& sink_stream_, std::string&& name_) |
| 35 | : sample_rate{sample_rate_}, format{format_}, release_callback{std::move(release_callback_)}, | 35 | : sample_rate{sample_rate_}, format{format_}, release_callback{std::move(release_callback_)}, |
| 36 | sink_stream{sink_stream_}, core_timing{core_timing_}, name{std::move(name_)} { | 36 | sink_stream{sink_stream_}, core_timing{core_timing_}, name{std::move(name_)} { |
| 37 | release_event = | 37 | release_event = Core::Timing::CreateEvent( |
| 38 | Core::Timing::CreateEvent(name, [this](std::uintptr_t, std::chrono::nanoseconds ns_late) { | 38 | name, [this](std::uintptr_t, s64 time, std::chrono::nanoseconds ns_late) { |
| 39 | ReleaseActiveBuffer(ns_late); | 39 | ReleaseActiveBuffer(ns_late); |
| 40 | return std::nullopt; | ||
| 40 | }); | 41 | }); |
| 41 | } | 42 | } |
| 42 | 43 | ||
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index 07b8e356b..5425637f5 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp | |||
| @@ -22,10 +22,11 @@ std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callbac | |||
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | struct CoreTiming::Event { | 24 | struct CoreTiming::Event { |
| 25 | u64 time; | 25 | s64 time; |
| 26 | u64 fifo_order; | 26 | u64 fifo_order; |
| 27 | std::uintptr_t user_data; | 27 | std::uintptr_t user_data; |
| 28 | std::weak_ptr<EventType> type; | 28 | std::weak_ptr<EventType> type; |
| 29 | s64 reschedule_time; | ||
| 29 | 30 | ||
| 30 | // Sort by time, unless the times are the same, in which case sort by | 31 | // Sort by time, unless the times are the same, in which case sort by |
| 31 | // the order added to the queue | 32 | // the order added to the queue |
| @@ -58,7 +59,8 @@ void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) { | |||
| 58 | event_fifo_id = 0; | 59 | event_fifo_id = 0; |
| 59 | shutting_down = false; | 60 | shutting_down = false; |
| 60 | ticks = 0; | 61 | ticks = 0; |
| 61 | const auto empty_timed_callback = [](std::uintptr_t, std::chrono::nanoseconds) {}; | 62 | const auto empty_timed_callback = [](std::uintptr_t, u64, std::chrono::nanoseconds) |
| 63 | -> std::optional<std::chrono::nanoseconds> { return std::nullopt; }; | ||
| 62 | ev_lost = CreateEvent("_lost_event", empty_timed_callback); | 64 | ev_lost = CreateEvent("_lost_event", empty_timed_callback); |
| 63 | if (is_multicore) { | 65 | if (is_multicore) { |
| 64 | worker_threads.emplace_back(ThreadEntry, std::ref(*this), 0); | 66 | worker_threads.emplace_back(ThreadEntry, std::ref(*this), 0); |
| @@ -76,6 +78,7 @@ void CoreTiming::Shutdown() { | |||
| 76 | thread.join(); | 78 | thread.join(); |
| 77 | } | 79 | } |
| 78 | worker_threads.clear(); | 80 | worker_threads.clear(); |
| 81 | pause_callbacks.clear(); | ||
| 79 | ClearPendingEvents(); | 82 | ClearPendingEvents(); |
| 80 | has_started = false; | 83 | has_started = false; |
| 81 | } | 84 | } |
| @@ -93,6 +96,14 @@ void CoreTiming::Pause(bool is_paused_) { | |||
| 93 | } | 96 | } |
| 94 | } | 97 | } |
| 95 | paused_state.store(is_paused_, std::memory_order_relaxed); | 98 | paused_state.store(is_paused_, std::memory_order_relaxed); |
| 99 | |||
| 100 | if (!is_paused_) { | ||
| 101 | pause_end_time = GetGlobalTimeNs().count(); | ||
| 102 | } | ||
| 103 | |||
| 104 | for (auto& cb : pause_callbacks) { | ||
| 105 | cb(is_paused_); | ||
| 106 | } | ||
| 96 | } | 107 | } |
| 97 | 108 | ||
| 98 | void CoreTiming::SyncPause(bool is_paused_) { | 109 | void CoreTiming::SyncPause(bool is_paused_) { |
| @@ -116,6 +127,14 @@ void CoreTiming::SyncPause(bool is_paused_) { | |||
| 116 | wait_signal_cv.wait(main_lock, [this] { return pause_count == 0; }); | 127 | wait_signal_cv.wait(main_lock, [this] { return pause_count == 0; }); |
| 117 | } | 128 | } |
| 118 | } | 129 | } |
| 130 | |||
| 131 | if (!is_paused_) { | ||
| 132 | pause_end_time = GetGlobalTimeNs().count(); | ||
| 133 | } | ||
| 134 | |||
| 135 | for (auto& cb : pause_callbacks) { | ||
| 136 | cb(is_paused_); | ||
| 137 | } | ||
| 119 | } | 138 | } |
| 120 | 139 | ||
| 121 | bool CoreTiming::IsRunning() const { | 140 | bool CoreTiming::IsRunning() const { |
| @@ -129,12 +148,30 @@ bool CoreTiming::HasPendingEvents() const { | |||
| 129 | 148 | ||
| 130 | void CoreTiming::ScheduleEvent(std::chrono::nanoseconds ns_into_future, | 149 | void CoreTiming::ScheduleEvent(std::chrono::nanoseconds ns_into_future, |
| 131 | const std::shared_ptr<EventType>& event_type, | 150 | const std::shared_ptr<EventType>& event_type, |
| 132 | std::uintptr_t user_data) { | 151 | std::uintptr_t user_data, bool absolute_time) { |
| 133 | 152 | ||
| 134 | std::unique_lock main_lock(event_mutex); | 153 | std::unique_lock main_lock(event_mutex); |
| 135 | const u64 timeout = static_cast<u64>((GetGlobalTimeNs() + ns_into_future).count()); | 154 | const auto next_time{absolute_time ? ns_into_future : GetGlobalTimeNs() + ns_into_future}; |
| 136 | 155 | ||
| 137 | event_queue.emplace_back(Event{timeout, event_fifo_id++, user_data, event_type}); | 156 | event_queue.emplace_back(Event{next_time.count(), event_fifo_id++, user_data, event_type, 0}); |
| 157 | pending_events.fetch_add(1, std::memory_order_relaxed); | ||
| 158 | |||
| 159 | std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>()); | ||
| 160 | |||
| 161 | if (is_multicore) { | ||
| 162 | event_cv.notify_one(); | ||
| 163 | } | ||
| 164 | } | ||
| 165 | |||
| 166 | void CoreTiming::ScheduleLoopingEvent(std::chrono::nanoseconds start_time, | ||
| 167 | std::chrono::nanoseconds resched_time, | ||
| 168 | const std::shared_ptr<EventType>& event_type, | ||
| 169 | std::uintptr_t user_data, bool absolute_time) { | ||
| 170 | std::unique_lock main_lock(event_mutex); | ||
| 171 | const auto next_time{absolute_time ? start_time : GetGlobalTimeNs() + start_time}; | ||
| 172 | |||
| 173 | event_queue.emplace_back( | ||
| 174 | Event{next_time.count(), event_fifo_id++, user_data, event_type, resched_time.count()}); | ||
| 138 | pending_events.fetch_add(1, std::memory_order_relaxed); | 175 | pending_events.fetch_add(1, std::memory_order_relaxed); |
| 139 | 176 | ||
| 140 | std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>()); | 177 | std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>()); |
| @@ -213,6 +250,11 @@ void CoreTiming::RemoveEvent(const std::shared_ptr<EventType>& event_type) { | |||
| 213 | } | 250 | } |
| 214 | } | 251 | } |
| 215 | 252 | ||
| 253 | void CoreTiming::RegisterPauseCallback(PauseCallback&& callback) { | ||
| 254 | std::unique_lock main_lock(event_mutex); | ||
| 255 | pause_callbacks.emplace_back(std::move(callback)); | ||
| 256 | } | ||
| 257 | |||
| 216 | std::optional<s64> CoreTiming::Advance() { | 258 | std::optional<s64> CoreTiming::Advance() { |
| 217 | global_timer = GetGlobalTimeNs().count(); | 259 | global_timer = GetGlobalTimeNs().count(); |
| 218 | 260 | ||
| @@ -223,14 +265,31 @@ std::optional<s64> CoreTiming::Advance() { | |||
| 223 | event_queue.pop_back(); | 265 | event_queue.pop_back(); |
| 224 | 266 | ||
| 225 | if (const auto event_type{evt.type.lock()}) { | 267 | if (const auto event_type{evt.type.lock()}) { |
| 226 | |||
| 227 | event_mutex.unlock(); | 268 | event_mutex.unlock(); |
| 228 | 269 | ||
| 229 | const s64 delay = static_cast<s64>(GetGlobalTimeNs().count() - evt.time); | 270 | const auto new_schedule_time{event_type->callback( |
| 230 | event_type->callback(evt.user_data, std::chrono::nanoseconds{delay}); | 271 | evt.user_data, evt.time, |
| 272 | std::chrono::nanoseconds{GetGlobalTimeNs().count() - evt.time})}; | ||
| 231 | 273 | ||
| 232 | event_mutex.lock(); | 274 | event_mutex.lock(); |
| 233 | pending_events.fetch_sub(1, std::memory_order_relaxed); | 275 | pending_events.fetch_sub(1, std::memory_order_relaxed); |
| 276 | |||
| 277 | if (evt.reschedule_time != 0) { | ||
| 278 | // If this event was scheduled into a pause, its time now is going to be way behind. | ||
| 279 | // Re-set this event to continue from the end of the pause. | ||
| 280 | auto next_time{evt.time + evt.reschedule_time}; | ||
| 281 | if (evt.time < pause_end_time) { | ||
| 282 | next_time = pause_end_time + evt.reschedule_time; | ||
| 283 | } | ||
| 284 | |||
| 285 | const auto next_schedule_time{new_schedule_time.has_value() | ||
| 286 | ? new_schedule_time.value().count() | ||
| 287 | : evt.reschedule_time}; | ||
| 288 | event_queue.emplace_back( | ||
| 289 | Event{next_time, event_fifo_id++, evt.user_data, evt.type, next_schedule_time}); | ||
| 290 | pending_events.fetch_add(1, std::memory_order_relaxed); | ||
| 291 | std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>()); | ||
| 292 | } | ||
| 234 | } | 293 | } |
| 235 | 294 | ||
| 236 | global_timer = GetGlobalTimeNs().count(); | 295 | global_timer = GetGlobalTimeNs().count(); |
diff --git a/src/core/core_timing.h b/src/core/core_timing.h index c52bffb3b..09b6ed81a 100644 --- a/src/core/core_timing.h +++ b/src/core/core_timing.h | |||
| @@ -20,8 +20,9 @@ | |||
| 20 | namespace Core::Timing { | 20 | namespace Core::Timing { |
| 21 | 21 | ||
| 22 | /// A callback that may be scheduled for a particular core timing event. | 22 | /// A callback that may be scheduled for a particular core timing event. |
| 23 | using TimedCallback = | 23 | using TimedCallback = std::function<std::optional<std::chrono::nanoseconds>( |
| 24 | std::function<void(std::uintptr_t user_data, std::chrono::nanoseconds ns_late)>; | 24 | std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)>; |
| 25 | using PauseCallback = std::function<void(bool paused)>; | ||
| 25 | 26 | ||
| 26 | /// Contains the characteristics of a particular event. | 27 | /// Contains the characteristics of a particular event. |
| 27 | struct EventType { | 28 | struct EventType { |
| @@ -93,7 +94,15 @@ public: | |||
| 93 | 94 | ||
| 94 | /// Schedules an event in core timing | 95 | /// Schedules an event in core timing |
| 95 | void ScheduleEvent(std::chrono::nanoseconds ns_into_future, | 96 | void ScheduleEvent(std::chrono::nanoseconds ns_into_future, |
| 96 | const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data = 0); | 97 | const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data = 0, |
| 98 | bool absolute_time = false); | ||
| 99 | |||
| 100 | /// Schedules an event which will automatically re-schedule itself with the given time, until | ||
| 101 | /// unscheduled | ||
| 102 | void ScheduleLoopingEvent(std::chrono::nanoseconds start_time, | ||
| 103 | std::chrono::nanoseconds resched_time, | ||
| 104 | const std::shared_ptr<EventType>& event_type, | ||
| 105 | std::uintptr_t user_data = 0, bool absolute_time = false); | ||
| 97 | 106 | ||
| 98 | void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data); | 107 | void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data); |
| 99 | 108 | ||
| @@ -125,6 +134,9 @@ public: | |||
| 125 | /// Checks for events manually and returns time in nanoseconds for next event, threadsafe. | 134 | /// Checks for events manually and returns time in nanoseconds for next event, threadsafe. |
| 126 | std::optional<s64> Advance(); | 135 | std::optional<s64> Advance(); |
| 127 | 136 | ||
| 137 | /// Register a callback function to be called when coretiming pauses. | ||
| 138 | void RegisterPauseCallback(PauseCallback&& callback); | ||
| 139 | |||
| 128 | private: | 140 | private: |
| 129 | struct Event; | 141 | struct Event; |
| 130 | 142 | ||
| @@ -136,7 +148,7 @@ private: | |||
| 136 | 148 | ||
| 137 | std::unique_ptr<Common::WallClock> clock; | 149 | std::unique_ptr<Common::WallClock> clock; |
| 138 | 150 | ||
| 139 | u64 global_timer = 0; | 151 | s64 global_timer = 0; |
| 140 | 152 | ||
| 141 | // The queue is a min-heap using std::make_heap/push_heap/pop_heap. | 153 | // The queue is a min-heap using std::make_heap/push_heap/pop_heap. |
| 142 | // We don't use std::priority_queue because we need to be able to serialize, unserialize and | 154 | // We don't use std::priority_queue because we need to be able to serialize, unserialize and |
| @@ -162,10 +174,13 @@ private: | |||
| 162 | bool shutting_down{}; | 174 | bool shutting_down{}; |
| 163 | bool is_multicore{}; | 175 | bool is_multicore{}; |
| 164 | size_t pause_count{}; | 176 | size_t pause_count{}; |
| 177 | s64 pause_end_time{}; | ||
| 165 | 178 | ||
| 166 | /// Cycle timing | 179 | /// Cycle timing |
| 167 | u64 ticks{}; | 180 | u64 ticks{}; |
| 168 | s64 downcount{}; | 181 | s64 downcount{}; |
| 182 | |||
| 183 | std::vector<PauseCallback> pause_callbacks{}; | ||
| 169 | }; | 184 | }; |
| 170 | 185 | ||
| 171 | /// Creates a core timing event with the given name and callback. | 186 | /// Creates a core timing event with the given name and callback. |
diff --git a/src/core/hardware_interrupt_manager.cpp b/src/core/hardware_interrupt_manager.cpp index d2d968a76..d08cc3315 100644 --- a/src/core/hardware_interrupt_manager.cpp +++ b/src/core/hardware_interrupt_manager.cpp | |||
| @@ -11,11 +11,14 @@ namespace Core::Hardware { | |||
| 11 | 11 | ||
| 12 | InterruptManager::InterruptManager(Core::System& system_in) : system(system_in) { | 12 | InterruptManager::InterruptManager(Core::System& system_in) : system(system_in) { |
| 13 | gpu_interrupt_event = Core::Timing::CreateEvent( | 13 | gpu_interrupt_event = Core::Timing::CreateEvent( |
| 14 | "GPUInterrupt", [this](std::uintptr_t message, std::chrono::nanoseconds) { | 14 | "GPUInterrupt", |
| 15 | [this](std::uintptr_t message, u64 time, | ||
| 16 | std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> { | ||
| 15 | auto nvdrv = system.ServiceManager().GetService<Service::Nvidia::NVDRV>("nvdrv"); | 17 | auto nvdrv = system.ServiceManager().GetService<Service::Nvidia::NVDRV>("nvdrv"); |
| 16 | const u32 syncpt = static_cast<u32>(message >> 32); | 18 | const u32 syncpt = static_cast<u32>(message >> 32); |
| 17 | const u32 value = static_cast<u32>(message); | 19 | const u32 value = static_cast<u32>(message); |
| 18 | nvdrv->SignalGPUInterruptSyncpt(syncpt, value); | 20 | nvdrv->SignalGPUInterruptSyncpt(syncpt, value); |
| 21 | return std::nullopt; | ||
| 19 | }); | 22 | }); |
| 20 | } | 23 | } |
| 21 | 24 | ||
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 0009193be..ee91a9b68 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -234,17 +234,19 @@ struct KernelCore::Impl { | |||
| 234 | 234 | ||
| 235 | void InitializePreemption(KernelCore& kernel) { | 235 | void InitializePreemption(KernelCore& kernel) { |
| 236 | preemption_event = Core::Timing::CreateEvent( | 236 | preemption_event = Core::Timing::CreateEvent( |
| 237 | "PreemptionCallback", [this, &kernel](std::uintptr_t, std::chrono::nanoseconds) { | 237 | "PreemptionCallback", |
| 238 | [this, &kernel](std::uintptr_t, s64 time, | ||
| 239 | std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> { | ||
| 238 | { | 240 | { |
| 239 | KScopedSchedulerLock lock(kernel); | 241 | KScopedSchedulerLock lock(kernel); |
| 240 | global_scheduler_context->PreemptThreads(); | 242 | global_scheduler_context->PreemptThreads(); |
| 241 | } | 243 | } |
| 242 | const auto time_interval = std::chrono::nanoseconds{std::chrono::milliseconds(10)}; | 244 | return std::nullopt; |
| 243 | system.CoreTiming().ScheduleEvent(time_interval, preemption_event); | ||
| 244 | }); | 245 | }); |
| 245 | 246 | ||
| 246 | const auto time_interval = std::chrono::nanoseconds{std::chrono::milliseconds(10)}; | 247 | const auto time_interval = std::chrono::nanoseconds{std::chrono::milliseconds(10)}; |
| 247 | system.CoreTiming().ScheduleEvent(time_interval, preemption_event); | 248 | system.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0), time_interval, |
| 249 | preemption_event); | ||
| 248 | } | 250 | } |
| 249 | 251 | ||
| 250 | void InitializeShutdownThreads() { | 252 | void InitializeShutdownThreads() { |
diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp index 2724c3782..5ee72c432 100644 --- a/src/core/hle/kernel/time_manager.cpp +++ b/src/core/hle/kernel/time_manager.cpp | |||
| @@ -11,15 +11,17 @@ | |||
| 11 | namespace Kernel { | 11 | namespace Kernel { |
| 12 | 12 | ||
| 13 | TimeManager::TimeManager(Core::System& system_) : system{system_} { | 13 | TimeManager::TimeManager(Core::System& system_) : system{system_} { |
| 14 | time_manager_event_type = | 14 | time_manager_event_type = Core::Timing::CreateEvent( |
| 15 | Core::Timing::CreateEvent("Kernel::TimeManagerCallback", | 15 | "Kernel::TimeManagerCallback", |
| 16 | [this](std::uintptr_t thread_handle, std::chrono::nanoseconds) { | 16 | [this](std::uintptr_t thread_handle, s64 time, |
| 17 | KThread* thread = reinterpret_cast<KThread*>(thread_handle); | 17 | std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> { |
| 18 | { | 18 | KThread* thread = reinterpret_cast<KThread*>(thread_handle); |
| 19 | KScopedSchedulerLock sl(system.Kernel()); | 19 | { |
| 20 | thread->OnTimer(); | 20 | KScopedSchedulerLock sl(system.Kernel()); |
| 21 | } | 21 | thread->OnTimer(); |
| 22 | }); | 22 | } |
| 23 | return std::nullopt; | ||
| 24 | }); | ||
| 23 | } | 25 | } |
| 24 | 26 | ||
| 25 | void TimeManager::ScheduleTimeEvent(KThread* thread, s64 nanoseconds) { | 27 | void TimeManager::ScheduleTimeEvent(KThread* thread, s64 nanoseconds) { |
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 78efffc50..88fcd53ec 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -74,26 +74,35 @@ IAppletResource::IAppletResource(Core::System& system_, | |||
| 74 | // Register update callbacks | 74 | // Register update callbacks |
| 75 | pad_update_event = Core::Timing::CreateEvent( | 75 | pad_update_event = Core::Timing::CreateEvent( |
| 76 | "HID::UpdatePadCallback", | 76 | "HID::UpdatePadCallback", |
| 77 | [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { | 77 | [this](std::uintptr_t user_data, s64 time, |
| 78 | std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { | ||
| 78 | const auto guard = LockService(); | 79 | const auto guard = LockService(); |
| 79 | UpdateControllers(user_data, ns_late); | 80 | UpdateControllers(user_data, ns_late); |
| 81 | return std::nullopt; | ||
| 80 | }); | 82 | }); |
| 81 | mouse_keyboard_update_event = Core::Timing::CreateEvent( | 83 | mouse_keyboard_update_event = Core::Timing::CreateEvent( |
| 82 | "HID::UpdateMouseKeyboardCallback", | 84 | "HID::UpdateMouseKeyboardCallback", |
| 83 | [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { | 85 | [this](std::uintptr_t user_data, s64 time, |
| 86 | std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { | ||
| 84 | const auto guard = LockService(); | 87 | const auto guard = LockService(); |
| 85 | UpdateMouseKeyboard(user_data, ns_late); | 88 | UpdateMouseKeyboard(user_data, ns_late); |
| 89 | return std::nullopt; | ||
| 86 | }); | 90 | }); |
| 87 | motion_update_event = Core::Timing::CreateEvent( | 91 | motion_update_event = Core::Timing::CreateEvent( |
| 88 | "HID::UpdateMotionCallback", | 92 | "HID::UpdateMotionCallback", |
| 89 | [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { | 93 | [this](std::uintptr_t user_data, s64 time, |
| 94 | std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { | ||
| 90 | const auto guard = LockService(); | 95 | const auto guard = LockService(); |
| 91 | UpdateMotion(user_data, ns_late); | 96 | UpdateMotion(user_data, ns_late); |
| 97 | return std::nullopt; | ||
| 92 | }); | 98 | }); |
| 93 | 99 | ||
| 94 | system.CoreTiming().ScheduleEvent(pad_update_ns, pad_update_event); | 100 | system.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0), pad_update_ns, |
| 95 | system.CoreTiming().ScheduleEvent(mouse_keyboard_update_ns, mouse_keyboard_update_event); | 101 | pad_update_event); |
| 96 | system.CoreTiming().ScheduleEvent(motion_update_ns, motion_update_event); | 102 | system.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0), mouse_keyboard_update_ns, |
| 103 | mouse_keyboard_update_event); | ||
| 104 | system.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0), motion_update_ns, | ||
| 105 | motion_update_event); | ||
| 97 | 106 | ||
| 98 | system.HIDCore().ReloadInputDevices(); | 107 | system.HIDCore().ReloadInputDevices(); |
| 99 | } | 108 | } |
| @@ -135,13 +144,6 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data, | |||
| 135 | } | 144 | } |
| 136 | controller->OnUpdate(core_timing); | 145 | controller->OnUpdate(core_timing); |
| 137 | } | 146 | } |
| 138 | |||
| 139 | // If ns_late is higher than the update rate ignore the delay | ||
| 140 | if (ns_late > pad_update_ns) { | ||
| 141 | ns_late = {}; | ||
| 142 | } | ||
| 143 | |||
| 144 | core_timing.ScheduleEvent(pad_update_ns - ns_late, pad_update_event); | ||
| 145 | } | 147 | } |
| 146 | 148 | ||
| 147 | void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data, | 149 | void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data, |
| @@ -150,26 +152,12 @@ void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data, | |||
| 150 | 152 | ||
| 151 | controllers[static_cast<size_t>(HidController::Mouse)]->OnUpdate(core_timing); | 153 | controllers[static_cast<size_t>(HidController::Mouse)]->OnUpdate(core_timing); |
| 152 | controllers[static_cast<size_t>(HidController::Keyboard)]->OnUpdate(core_timing); | 154 | controllers[static_cast<size_t>(HidController::Keyboard)]->OnUpdate(core_timing); |
| 153 | |||
| 154 | // If ns_late is higher than the update rate ignore the delay | ||
| 155 | if (ns_late > mouse_keyboard_update_ns) { | ||
| 156 | ns_late = {}; | ||
| 157 | } | ||
| 158 | |||
| 159 | core_timing.ScheduleEvent(mouse_keyboard_update_ns - ns_late, mouse_keyboard_update_event); | ||
| 160 | } | 155 | } |
| 161 | 156 | ||
| 162 | void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { | 157 | void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { |
| 163 | auto& core_timing = system.CoreTiming(); | 158 | auto& core_timing = system.CoreTiming(); |
| 164 | 159 | ||
| 165 | controllers[static_cast<size_t>(HidController::NPad)]->OnMotionUpdate(core_timing); | 160 | controllers[static_cast<size_t>(HidController::NPad)]->OnMotionUpdate(core_timing); |
| 166 | |||
| 167 | // If ns_late is higher than the update rate ignore the delay | ||
| 168 | if (ns_late > motion_update_ns) { | ||
| 169 | ns_late = {}; | ||
| 170 | } | ||
| 171 | |||
| 172 | core_timing.ScheduleEvent(motion_update_ns - ns_late, motion_update_event); | ||
| 173 | } | 161 | } |
| 174 | 162 | ||
| 175 | class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> { | 163 | class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> { |
diff --git a/src/core/hle/service/hid/hidbus.cpp b/src/core/hle/service/hid/hidbus.cpp index fa6153b4c..5e20e6830 100644 --- a/src/core/hle/service/hid/hidbus.cpp +++ b/src/core/hle/service/hid/hidbus.cpp | |||
| @@ -50,12 +50,15 @@ HidBus::HidBus(Core::System& system_) | |||
| 50 | // Register update callbacks | 50 | // Register update callbacks |
| 51 | hidbus_update_event = Core::Timing::CreateEvent( | 51 | hidbus_update_event = Core::Timing::CreateEvent( |
| 52 | "Hidbus::UpdateCallback", | 52 | "Hidbus::UpdateCallback", |
| 53 | [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { | 53 | [this](std::uintptr_t user_data, s64 time, |
| 54 | std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { | ||
| 54 | const auto guard = LockService(); | 55 | const auto guard = LockService(); |
| 55 | UpdateHidbus(user_data, ns_late); | 56 | UpdateHidbus(user_data, ns_late); |
| 57 | return std::nullopt; | ||
| 56 | }); | 58 | }); |
| 57 | 59 | ||
| 58 | system_.CoreTiming().ScheduleEvent(hidbus_update_ns, hidbus_update_event); | 60 | system_.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0), hidbus_update_ns, |
| 61 | hidbus_update_event); | ||
| 59 | } | 62 | } |
| 60 | 63 | ||
| 61 | HidBus::~HidBus() { | 64 | HidBus::~HidBus() { |
| @@ -63,8 +66,6 @@ HidBus::~HidBus() { | |||
| 63 | } | 66 | } |
| 64 | 67 | ||
| 65 | void HidBus::UpdateHidbus(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { | 68 | void HidBus::UpdateHidbus(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { |
| 66 | auto& core_timing = system.CoreTiming(); | ||
| 67 | |||
| 68 | if (is_hidbus_enabled) { | 69 | if (is_hidbus_enabled) { |
| 69 | for (std::size_t i = 0; i < devices.size(); ++i) { | 70 | for (std::size_t i = 0; i < devices.size(); ++i) { |
| 70 | if (!devices[i].is_device_initializated) { | 71 | if (!devices[i].is_device_initializated) { |
| @@ -82,13 +83,6 @@ void HidBus::UpdateHidbus(std::uintptr_t user_data, std::chrono::nanoseconds ns_ | |||
| 82 | sizeof(HidbusStatusManagerEntry)); | 83 | sizeof(HidbusStatusManagerEntry)); |
| 83 | } | 84 | } |
| 84 | } | 85 | } |
| 85 | |||
| 86 | // If ns_late is higher than the update rate ignore the delay | ||
| 87 | if (ns_late > hidbus_update_ns) { | ||
| 88 | ns_late = {}; | ||
| 89 | } | ||
| 90 | |||
| 91 | core_timing.ScheduleEvent(hidbus_update_ns - ns_late, hidbus_update_event); | ||
| 92 | } | 86 | } |
| 93 | 87 | ||
| 94 | std::optional<std::size_t> HidBus::GetDeviceIndexFromHandle(BusHandle handle) const { | 88 | std::optional<std::size_t> HidBus::GetDeviceIndexFromHandle(BusHandle handle) const { |
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index 2b2985a2d..600b19b3f 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp | |||
| @@ -67,21 +67,20 @@ NVFlinger::NVFlinger(Core::System& system_, HosBinderDriverServer& hos_binder_dr | |||
| 67 | 67 | ||
| 68 | // Schedule the screen composition events | 68 | // Schedule the screen composition events |
| 69 | composition_event = Core::Timing::CreateEvent( | 69 | composition_event = Core::Timing::CreateEvent( |
| 70 | "ScreenComposition", [this](std::uintptr_t, std::chrono::nanoseconds ns_late) { | 70 | "ScreenComposition", |
| 71 | [this](std::uintptr_t, s64 time, | ||
| 72 | std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { | ||
| 71 | const auto lock_guard = Lock(); | 73 | const auto lock_guard = Lock(); |
| 72 | Compose(); | 74 | Compose(); |
| 73 | 75 | ||
| 74 | const auto ticks = std::chrono::nanoseconds{GetNextTicks()}; | 76 | return std::chrono::nanoseconds(GetNextTicks()) - ns_late; |
| 75 | const auto ticks_delta = ticks - ns_late; | ||
| 76 | const auto future_ns = std::max(std::chrono::nanoseconds::zero(), ticks_delta); | ||
| 77 | |||
| 78 | this->system.CoreTiming().ScheduleEvent(future_ns, composition_event); | ||
| 79 | }); | 77 | }); |
| 80 | 78 | ||
| 81 | if (system.IsMulticore()) { | 79 | if (system.IsMulticore()) { |
| 82 | vsync_thread = std::jthread([this](std::stop_token token) { SplitVSync(token); }); | 80 | vsync_thread = std::jthread([this](std::stop_token token) { SplitVSync(token); }); |
| 83 | } else { | 81 | } else { |
| 84 | system.CoreTiming().ScheduleEvent(frame_ns, composition_event); | 82 | system.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0), frame_ns, |
| 83 | composition_event); | ||
| 85 | } | 84 | } |
| 86 | } | 85 | } |
| 87 | 86 | ||
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp index 5f71f0ff5..09a02d2ac 100644 --- a/src/core/memory/cheat_engine.cpp +++ b/src/core/memory/cheat_engine.cpp | |||
| @@ -184,10 +184,12 @@ CheatEngine::~CheatEngine() { | |||
| 184 | void CheatEngine::Initialize() { | 184 | void CheatEngine::Initialize() { |
| 185 | event = Core::Timing::CreateEvent( | 185 | event = Core::Timing::CreateEvent( |
| 186 | "CheatEngine::FrameCallback::" + Common::HexToString(metadata.main_nso_build_id), | 186 | "CheatEngine::FrameCallback::" + Common::HexToString(metadata.main_nso_build_id), |
| 187 | [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { | 187 | [this](std::uintptr_t user_data, s64 time, |
| 188 | std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { | ||
| 188 | FrameCallback(user_data, ns_late); | 189 | FrameCallback(user_data, ns_late); |
| 190 | return std::nullopt; | ||
| 189 | }); | 191 | }); |
| 190 | core_timing.ScheduleEvent(CHEAT_ENGINE_NS, event); | 192 | core_timing.ScheduleLoopingEvent(std::chrono::nanoseconds(0), CHEAT_ENGINE_NS, event); |
| 191 | 193 | ||
| 192 | metadata.process_id = system.CurrentProcess()->GetProcessID(); | 194 | metadata.process_id = system.CurrentProcess()->GetProcessID(); |
| 193 | metadata.title_id = system.GetCurrentProcessProgramID(); | 195 | metadata.title_id = system.GetCurrentProcessProgramID(); |
| @@ -237,8 +239,6 @@ void CheatEngine::FrameCallback(std::uintptr_t, std::chrono::nanoseconds ns_late | |||
| 237 | MICROPROFILE_SCOPE(Cheat_Engine); | 239 | MICROPROFILE_SCOPE(Cheat_Engine); |
| 238 | 240 | ||
| 239 | vm.Execute(metadata); | 241 | vm.Execute(metadata); |
| 240 | |||
| 241 | core_timing.ScheduleEvent(CHEAT_ENGINE_NS - ns_late, event); | ||
| 242 | } | 242 | } |
| 243 | 243 | ||
| 244 | } // namespace Core::Memory | 244 | } // namespace Core::Memory |
diff --git a/src/core/tools/freezer.cpp b/src/core/tools/freezer.cpp index 5cc99fbe4..98ebbbf32 100644 --- a/src/core/tools/freezer.cpp +++ b/src/core/tools/freezer.cpp | |||
| @@ -53,8 +53,10 @@ Freezer::Freezer(Core::Timing::CoreTiming& core_timing_, Core::Memory::Memory& m | |||
| 53 | : core_timing{core_timing_}, memory{memory_} { | 53 | : core_timing{core_timing_}, memory{memory_} { |
| 54 | event = Core::Timing::CreateEvent( | 54 | event = Core::Timing::CreateEvent( |
| 55 | "MemoryFreezer::FrameCallback", | 55 | "MemoryFreezer::FrameCallback", |
| 56 | [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { | 56 | [this](std::uintptr_t user_data, s64 time, |
| 57 | std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { | ||
| 57 | FrameCallback(user_data, ns_late); | 58 | FrameCallback(user_data, ns_late); |
| 59 | return std::nullopt; | ||
| 58 | }); | 60 | }); |
| 59 | core_timing.ScheduleEvent(memory_freezer_ns, event); | 61 | core_timing.ScheduleEvent(memory_freezer_ns, event); |
| 60 | } | 62 | } |
diff --git a/src/tests/core/core_timing.cpp b/src/tests/core/core_timing.cpp index e687416a8..894975e6f 100644 --- a/src/tests/core/core_timing.cpp +++ b/src/tests/core/core_timing.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include <cstdlib> | 9 | #include <cstdlib> |
| 10 | #include <memory> | 10 | #include <memory> |
| 11 | #include <mutex> | 11 | #include <mutex> |
| 12 | #include <optional> | ||
| 12 | #include <string> | 13 | #include <string> |
| 13 | 14 | ||
| 14 | #include "core/core.h" | 15 | #include "core/core.h" |
| @@ -25,13 +26,15 @@ u64 expected_callback = 0; | |||
| 25 | std::mutex control_mutex; | 26 | std::mutex control_mutex; |
| 26 | 27 | ||
| 27 | template <unsigned int IDX> | 28 | template <unsigned int IDX> |
| 28 | void HostCallbackTemplate(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { | 29 | std::optional<std::chrono::nanoseconds> HostCallbackTemplate(std::uintptr_t user_data, s64 time, |
| 30 | std::chrono::nanoseconds ns_late) { | ||
| 29 | std::unique_lock<std::mutex> lk(control_mutex); | 31 | std::unique_lock<std::mutex> lk(control_mutex); |
| 30 | static_assert(IDX < CB_IDS.size(), "IDX out of range"); | 32 | static_assert(IDX < CB_IDS.size(), "IDX out of range"); |
| 31 | callbacks_ran_flags.set(IDX); | 33 | callbacks_ran_flags.set(IDX); |
| 32 | REQUIRE(CB_IDS[IDX] == user_data); | 34 | REQUIRE(CB_IDS[IDX] == user_data); |
| 33 | delays[IDX] = ns_late.count(); | 35 | delays[IDX] = ns_late.count(); |
| 34 | ++expected_callback; | 36 | ++expected_callback; |
| 37 | return std::nullopt; | ||
| 35 | } | 38 | } |
| 36 | 39 | ||
| 37 | struct ScopeInit final { | 40 | struct ScopeInit final { |