diff options
author | bunnei <bunneidev@gmail.com> | 2022-09-17 20:10:54 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-09-17 20:10:54 +0200 |
commit | 9c32f29af18f5412ea4ba9f15fe0da3805e0d858 (patch) | |
tree | 63f5b2a5b5ad49179067d01e34c11fb2a7510bd8 /src/core/core_timing.cpp | |
parent | Merge pull request #8914 from lioncash/audio-const (diff) | |
parent | core_timing: Sleep in discrete intervals, yield during spin (diff) | |
download | yuzu-9c32f29af18f5412ea4ba9f15fe0da3805e0d858.tar yuzu-9c32f29af18f5412ea4ba9f15fe0da3805e0d858.tar.gz yuzu-9c32f29af18f5412ea4ba9f15fe0da3805e0d858.tar.bz2 yuzu-9c32f29af18f5412ea4ba9f15fe0da3805e0d858.tar.lz yuzu-9c32f29af18f5412ea4ba9f15fe0da3805e0d858.tar.xz yuzu-9c32f29af18f5412ea4ba9f15fe0da3805e0d858.tar.zst yuzu-9c32f29af18f5412ea4ba9f15fe0da3805e0d858.zip |
Diffstat (limited to 'src/core/core_timing.cpp')
-rw-r--r-- | src/core/core_timing.cpp | 53 |
1 files changed, 37 insertions, 16 deletions
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index 5375a5d59..f6c4567ba 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp @@ -134,13 +134,17 @@ void CoreTiming::ScheduleLoopingEvent(std::chrono::nanoseconds start_time, std::chrono::nanoseconds resched_time, const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data, bool absolute_time) { - std::scoped_lock scope{basic_lock}; - const auto next_time{absolute_time ? start_time : GetGlobalTimeNs() + start_time}; + { + std::scoped_lock scope{basic_lock}; + const auto next_time{absolute_time ? start_time : GetGlobalTimeNs() + start_time}; + + event_queue.emplace_back( + Event{next_time.count(), event_fifo_id++, user_data, event_type, resched_time.count()}); - event_queue.emplace_back( - Event{next_time.count(), event_fifo_id++, user_data, event_type, resched_time.count()}); + std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>()); + } - std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>()); + event.Set(); } void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type, @@ -229,17 +233,17 @@ std::optional<s64> CoreTiming::Advance() { basic_lock.lock(); if (evt.reschedule_time != 0) { + const auto next_schedule_time{new_schedule_time.has_value() + ? new_schedule_time.value().count() + : evt.reschedule_time}; + // If this event was scheduled into a pause, its time now is going to be way behind. // Re-set this event to continue from the end of the pause. - auto next_time{evt.time + evt.reschedule_time}; + auto next_time{evt.time + next_schedule_time}; if (evt.time < pause_end_time) { - next_time = pause_end_time + evt.reschedule_time; + next_time = pause_end_time + next_schedule_time; } - const auto next_schedule_time{new_schedule_time.has_value() - ? new_schedule_time.value().count() - : evt.reschedule_time}; - event_queue.emplace_back( Event{next_time, event_fifo_id++, evt.user_data, evt.type, next_schedule_time}); std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>()); @@ -250,8 +254,7 @@ std::optional<s64> CoreTiming::Advance() { } if (!event_queue.empty()) { - const s64 next_time = event_queue.front().time - global_timer; - return next_time; + return event_queue.front().time; } else { return std::nullopt; } @@ -264,11 +267,29 @@ void CoreTiming::ThreadLoop() { paused_set = false; const auto next_time = Advance(); if (next_time) { - if (*next_time > 0) { - std::chrono::nanoseconds next_time_ns = std::chrono::nanoseconds(*next_time); - event.WaitFor(next_time_ns); + // There are more events left in the queue, wait until the next event. + const auto wait_time = *next_time - GetGlobalTimeNs().count(); + if (wait_time > 0) { + // Assume a timer resolution of 1ms. + static constexpr s64 TimerResolutionNS = 1000000; + + // Sleep in discrete intervals of the timer resolution, and spin the rest. + const auto sleep_time = wait_time - (wait_time % TimerResolutionNS); + if (sleep_time > 0) { + event.WaitFor(std::chrono::nanoseconds(sleep_time)); + } + + while (!paused && !event.IsSet() && GetGlobalTimeNs().count() < *next_time) { + // Yield to reduce thread starvation. + std::this_thread::yield(); + } + + if (event.IsSet()) { + event.Reset(); + } } } else { + // Queue is empty, wait until another event is scheduled and signals us to continue. wait_set = true; event.Wait(); } |