diff options
Diffstat (limited to 'src/core/core_timing.cpp')
| -rw-r--r-- | src/core/core_timing.cpp | 82 |
1 files changed, 71 insertions, 11 deletions
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index 29e7dba9b..2dbb99c8b 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp @@ -20,10 +20,11 @@ std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callbac } struct CoreTiming::Event { - u64 time; + s64 time; u64 fifo_order; std::uintptr_t user_data; std::weak_ptr<EventType> type; + s64 reschedule_time; // Sort by time, unless the times are the same, in which case sort by // the order added to the queue @@ -45,7 +46,7 @@ void CoreTiming::ThreadEntry(CoreTiming& instance) { constexpr char name[] = "yuzu:HostTiming"; MicroProfileOnThreadCreate(name); Common::SetCurrentThreadName(name); - Common::SetCurrentThreadPriority(Common::ThreadPriority::VeryHigh); + Common::SetCurrentThreadPriority(Common::ThreadPriority::Critical); instance.on_thread_init(); instance.ThreadLoop(); MicroProfileOnThreadExit(); @@ -56,7 +57,8 @@ void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) { event_fifo_id = 0; shutting_down = false; ticks = 0; - const auto empty_timed_callback = [](std::uintptr_t, std::chrono::nanoseconds) {}; + const auto empty_timed_callback = [](std::uintptr_t, u64, std::chrono::nanoseconds) + -> std::optional<std::chrono::nanoseconds> { return std::nullopt; }; ev_lost = CreateEvent("_lost_event", empty_timed_callback); if (is_multicore) { timer_thread = std::make_unique<std::thread>(ThreadEntry, std::ref(*this)); @@ -71,6 +73,7 @@ void CoreTiming::Shutdown() { if (timer_thread) { timer_thread->join(); } + pause_callbacks.clear(); ClearPendingEvents(); timer_thread.reset(); has_started = false; @@ -79,12 +82,21 @@ void CoreTiming::Shutdown() { void CoreTiming::Pause(bool is_paused) { paused = is_paused; pause_event.Set(); + + if (!is_paused) { + pause_end_time = GetGlobalTimeNs().count(); + } + + for (auto& cb : pause_callbacks) { + cb(is_paused); + } } void CoreTiming::SyncPause(bool is_paused) { if (is_paused == paused && paused_set == paused) { return; } + Pause(is_paused); if (timer_thread) { if (!is_paused) { @@ -94,6 +106,14 @@ void CoreTiming::SyncPause(bool is_paused) { while (paused_set != is_paused) ; } + + if (!is_paused) { + pause_end_time = GetGlobalTimeNs().count(); + } + + for (auto& cb : pause_callbacks) { + cb(is_paused); + } } bool CoreTiming::IsRunning() const { @@ -106,18 +126,32 @@ bool CoreTiming::HasPendingEvents() const { void CoreTiming::ScheduleEvent(std::chrono::nanoseconds ns_into_future, const std::shared_ptr<EventType>& event_type, - std::uintptr_t user_data) { + std::uintptr_t user_data, bool absolute_time) { { std::scoped_lock scope{basic_lock}; - const u64 timeout = static_cast<u64>((GetGlobalTimeNs() + ns_into_future).count()); - - event_queue.emplace_back(Event{timeout, event_fifo_id++, user_data, event_type}); + const auto next_time{absolute_time ? ns_into_future : GetGlobalTimeNs() + ns_into_future}; + event_queue.emplace_back( + Event{next_time.count(), event_fifo_id++, user_data, event_type, 0}); std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>()); } + event.Set(); } +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}; + + 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<>()); +} + void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data) { std::scoped_lock scope{basic_lock}; @@ -185,6 +219,11 @@ void CoreTiming::RemoveEvent(const std::shared_ptr<EventType>& event_type) { } } +void CoreTiming::RegisterPauseCallback(PauseCallback&& callback) { + std::scoped_lock lock{basic_lock}; + pause_callbacks.emplace_back(std::move(callback)); +} + std::optional<s64> CoreTiming::Advance() { std::scoped_lock lock{advance_lock, basic_lock}; global_timer = GetGlobalTimeNs().count(); @@ -193,14 +232,34 @@ std::optional<s64> CoreTiming::Advance() { Event evt = std::move(event_queue.front()); std::pop_heap(event_queue.begin(), event_queue.end(), std::greater<>()); event_queue.pop_back(); - basic_lock.unlock(); if (const auto event_type{evt.type.lock()}) { - event_type->callback( - evt.user_data, std::chrono::nanoseconds{static_cast<s64>(global_timer - evt.time)}); + basic_lock.unlock(); + + const auto new_schedule_time{event_type->callback( + evt.user_data, evt.time, + std::chrono::nanoseconds{GetGlobalTimeNs().count() - evt.time})}; + + basic_lock.lock(); + + if (evt.reschedule_time != 0) { + // 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}; + if (evt.time < pause_end_time) { + next_time = pause_end_time + evt.reschedule_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<>()); + } } - basic_lock.lock(); global_timer = GetGlobalTimeNs().count(); } @@ -229,6 +288,7 @@ void CoreTiming::ThreadLoop() { } wait_set = false; } + paused_set = true; clock->Pause(true); pause_event.Wait(); |
