From 8b50c660dfce50a07c2b2aa3c1b6b8642259a944 Mon Sep 17 00:00:00 2001
From: Lioncash <mathew1800@gmail.com>
Date: Wed, 15 Jul 2020 18:30:06 -0400
Subject: [PATCH] core_timing: Make use of std::chrono with ScheduleEvent

---
 src/audio_core/stream.cpp                    | 14 ++++++--------
 src/audio_core/stream.h                      |  6 ++----
 src/core/core_timing.cpp                     |  8 ++++----
 src/core/core_timing.h                       |  8 ++++----
 src/core/hardware_interrupt_manager.cpp      |  2 +-
 src/core/hle/kernel/kernel.cpp               |  6 ++++--
 src/core/hle/kernel/server_session.cpp       |  4 ++--
 src/core/hle/kernel/time_manager.cpp         |  3 ++-
 src/core/hle/service/hid/hid.cpp             | 12 +++++++-----
 src/core/hle/service/nvflinger/nvflinger.cpp | 15 +++++++++------
 src/core/memory/cheat_engine.cpp             |  7 ++++---
 src/core/tools/freezer.cpp                   |  9 +++++----
 src/tests/core/core_timing.cpp               | 13 ++++++++-----
 13 files changed, 58 insertions(+), 49 deletions(-)

diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp
index aab3e979a..abd8576e2 100644
--- a/src/audio_core/stream.cpp
+++ b/src/audio_core/stream.cpp
@@ -59,11 +59,9 @@ Stream::State Stream::GetState() const {
     return state;
 }
 
-s64 Stream::GetBufferReleaseNS(const Buffer& buffer) const {
+std::chrono::nanoseconds Stream::GetBufferReleaseNS(const Buffer& buffer) const {
     const std::size_t num_samples{buffer.GetSamples().size() / GetNumChannels()};
-    const auto ns =
-        std::chrono::nanoseconds((static_cast<u64>(num_samples) * 1000000000ULL) / sample_rate);
-    return ns.count();
+    return std::chrono::nanoseconds((static_cast<u64>(num_samples) * 1000000000ULL) / sample_rate);
 }
 
 static void VolumeAdjustSamples(std::vector<s16>& samples, float game_volume) {
@@ -105,10 +103,10 @@ void Stream::PlayNextBuffer(s64 cycles_late) {
 
     sink_stream.EnqueueSamples(GetNumChannels(), active_buffer->GetSamples());
 
-    core_timing.ScheduleEvent(
-        GetBufferReleaseNS(*active_buffer) -
-            (Settings::values.enable_audio_stretching.GetValue() ? 0 : cycles_late),
-        release_event, {});
+    const auto time_stretch_delta = std::chrono::nanoseconds{
+        Settings::values.enable_audio_stretching.GetValue() ? 0 : cycles_late};
+    const auto future_time = GetBufferReleaseNS(*active_buffer) - time_stretch_delta;
+    core_timing.ScheduleEvent(future_time, release_event, {});
 }
 
 void Stream::ReleaseActiveBuffer(s64 cycles_late) {
diff --git a/src/audio_core/stream.h b/src/audio_core/stream.h
index 524376257..2febd647c 100644
--- a/src/audio_core/stream.h
+++ b/src/audio_core/stream.h
@@ -4,6 +4,7 @@
 
 #pragma once
 
+#include <chrono>
 #include <functional>
 #include <memory>
 #include <string>
@@ -96,10 +97,7 @@ private:
     void ReleaseActiveBuffer(s64 cycles_late = 0);
 
     /// Gets the number of core cycles when the specified buffer will be released
-    s64 GetBufferReleaseNS(const Buffer& buffer) const;
-
-    /// Gets the number of core cycles when the specified buffer will be released
-    s64 GetBufferReleaseNSHostTiming(const Buffer& buffer) const;
+    std::chrono::nanoseconds GetBufferReleaseNS(const Buffer& buffer) const;
 
     u32 sample_rate;                  ///< Sample rate of the stream
     Format format;                    ///< Format of the stream
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index a63e60461..a5d084e08 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -53,7 +53,7 @@ void CoreTiming::ThreadEntry(CoreTiming& instance) {
     instance.ThreadLoop();
 }
 
-void CoreTiming::Initialize(std::function<void(void)>&& on_thread_init_) {
+void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) {
     on_thread_init = std::move(on_thread_init_);
     event_fifo_id = 0;
     shutting_down = false;
@@ -106,11 +106,11 @@ bool CoreTiming::HasPendingEvents() const {
     return !(wait_set && event_queue.empty());
 }
 
-void CoreTiming::ScheduleEvent(s64 ns_into_future, const std::shared_ptr<EventType>& event_type,
-                               u64 userdata) {
+void CoreTiming::ScheduleEvent(std::chrono::nanoseconds ns_into_future,
+                               const std::shared_ptr<EventType>& event_type, u64 userdata) {
     {
         std::scoped_lock scope{basic_lock};
-        const u64 timeout = static_cast<u64>(GetGlobalTimeNs().count() + ns_into_future);
+        const u64 timeout = static_cast<u64>((GetGlobalTimeNs() + ns_into_future).count());
 
         event_queue.emplace_back(Event{timeout, event_fifo_id++, userdata, event_type});
 
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index 72faaab64..9b9f18daf 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -62,7 +62,7 @@ public:
 
     /// CoreTiming begins at the boundary of timing slice -1. An initial call to Advance() is
     /// required to end slice - 1 and start slice 0 before the first cycle of code is executed.
-    void Initialize(std::function<void(void)>&& on_thread_init_);
+    void Initialize(std::function<void()>&& on_thread_init_);
 
     /// Tears down all timing related functionality.
     void Shutdown();
@@ -95,8 +95,8 @@ public:
     bool HasPendingEvents() const;
 
     /// Schedules an event in core timing
-    void ScheduleEvent(s64 ns_into_future, const std::shared_ptr<EventType>& event_type,
-                       u64 userdata = 0);
+    void ScheduleEvent(std::chrono::nanoseconds ns_into_future,
+                       const std::shared_ptr<EventType>& event_type, u64 userdata = 0);
 
     void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, u64 userdata);
 
@@ -161,7 +161,7 @@ private:
     std::atomic<bool> wait_set{};
     std::atomic<bool> shutting_down{};
     std::atomic<bool> has_started{};
-    std::function<void(void)> on_thread_init{};
+    std::function<void()> on_thread_init{};
 
     bool is_multicore{};
 
diff --git a/src/core/hardware_interrupt_manager.cpp b/src/core/hardware_interrupt_manager.cpp
index c629d9fa1..e7fd71e2e 100644
--- a/src/core/hardware_interrupt_manager.cpp
+++ b/src/core/hardware_interrupt_manager.cpp
@@ -23,7 +23,7 @@ InterruptManager::~InterruptManager() = default;
 
 void InterruptManager::GPUInterruptSyncpt(const u32 syncpoint_id, const u32 value) {
     const u64 msg = (static_cast<u64>(syncpoint_id) << 32ULL) | value;
-    system.CoreTiming().ScheduleEvent(10, gpu_interrupt_event, msg);
+    system.CoreTiming().ScheduleEvent(std::chrono::nanoseconds{10}, gpu_interrupt_event, msg);
 }
 
 } // namespace Core::Hardware
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 1f2af7a1b..35fb270b8 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -149,11 +149,13 @@ struct KernelCore::Impl {
                     SchedulerLock lock(kernel);
                     global_scheduler.PreemptThreads();
                 }
-                s64 time_interval = Core::Timing::msToCycles(std::chrono::milliseconds(10));
+                const auto time_interval = std::chrono::nanoseconds{
+                    Core::Timing::msToCycles(std::chrono::milliseconds(10))};
                 system.CoreTiming().ScheduleEvent(time_interval, preemption_event);
             });
 
-        s64 time_interval = Core::Timing::msToCycles(std::chrono::milliseconds(10));
+        const auto time_interval =
+            std::chrono::nanoseconds{Core::Timing::msToCycles(std::chrono::milliseconds(10))};
         system.CoreTiming().ScheduleEvent(time_interval, preemption_event);
     }
 
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index 7b23a6889..8c32f28b5 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -184,8 +184,8 @@ ResultCode ServerSession::CompleteSyncRequest() {
 
 ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread,
                                             Core::Memory::Memory& memory) {
-    ResultCode result = QueueSyncRequest(std::move(thread), memory);
-    const u64 delay = kernel.IsMulticore() ? 0U : 20000U;
+    const ResultCode result = QueueSyncRequest(std::move(thread), memory);
+    const auto delay = std::chrono::nanoseconds{kernel.IsMulticore() ? 0 : 20000};
     Core::System::GetInstance().CoreTiming().ScheduleEvent(delay, request_event, {});
     return result;
 }
diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp
index 941305e8e..ebb1e5568 100644
--- a/src/core/hle/kernel/time_manager.cpp
+++ b/src/core/hle/kernel/time_manager.cpp
@@ -34,7 +34,8 @@ void TimeManager::ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64
         ASSERT(timetask);
         ASSERT(timetask->GetStatus() != ThreadStatus::Ready);
         ASSERT(timetask->GetStatus() != ThreadStatus::WaitMutex);
-        system.CoreTiming().ScheduleEvent(nanoseconds, time_manager_event_type, event_handle);
+        system.CoreTiming().ScheduleEvent(std::chrono::nanoseconds{nanoseconds},
+                                          time_manager_event_type, event_handle);
     } else {
         event_handle = InvalidHandle;
     }
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index e9020e0dc..62c942eac 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -39,9 +39,10 @@ namespace Service::HID {
 
 // Updating period for each HID device.
 // TODO(ogniK): Find actual polling rate of hid
-constexpr s64 pad_update_ticks = static_cast<s64>(1000000000 / 66);
-[[maybe_unused]] constexpr s64 accelerometer_update_ticks = static_cast<s64>(1000000000 / 100);
-[[maybe_unused]] constexpr s64 gyroscope_update_ticks = static_cast<s64>(1000000000 / 100);
+constexpr auto pad_update_ns = std::chrono::nanoseconds{1000000000 / 66};
+[[maybe_unused]] constexpr auto accelerometer_update_ns =
+    std::chrono::nanoseconds{1000000000 / 100};
+[[maybe_unused]] constexpr auto gyroscope_update_ticks = std::chrono::nanoseconds{1000000000 / 100};
 constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000;
 
 IAppletResource::IAppletResource(Core::System& system)
@@ -82,7 +83,7 @@ IAppletResource::IAppletResource(Core::System& system)
 
     // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?)
 
-    system.CoreTiming().ScheduleEvent(pad_update_ticks, pad_update_event);
+    system.CoreTiming().ScheduleEvent(pad_update_ns, pad_update_event);
 
     ReloadInputDevices();
 }
@@ -118,7 +119,8 @@ void IAppletResource::UpdateControllers(u64 userdata, s64 ns_late) {
         controller->OnUpdate(core_timing, shared_mem->GetPointer(), SHARED_MEMORY_SIZE);
     }
 
-    core_timing.ScheduleEvent(pad_update_ticks - ns_late, pad_update_event);
+    const auto future_ns = pad_update_ns - std::chrono::nanoseconds{ns_late};
+    core_timing.ScheduleEvent(future_ns, pad_update_event);
 }
 
 class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> {
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index 2f44d3779..76672264d 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -28,8 +28,7 @@
 
 namespace Service::NVFlinger {
 
-constexpr s64 frame_ticks = static_cast<s64>(1000000000 / 60);
-constexpr s64 frame_ticks_30fps = static_cast<s64>(1000000000 / 30);
+constexpr auto frame_ns = std::chrono::nanoseconds{1000000000 / 60};
 
 void NVFlinger::VSyncThread(NVFlinger& nv_flinger) {
     nv_flinger.SplitVSync();
@@ -71,16 +70,20 @@ NVFlinger::NVFlinger(Core::System& system) : system(system) {
         Core::Timing::CreateEvent("ScreenComposition", [this](u64 userdata, s64 ns_late) {
             Lock();
             Compose();
-            const auto ticks = GetNextTicks();
-            this->system.CoreTiming().ScheduleEvent(std::max<s64>(0LL, ticks - ns_late),
-                                                    composition_event);
+
+            const auto ticks = std::chrono::nanoseconds{GetNextTicks()};
+            const auto ticks_delta = ticks - std::chrono::nanoseconds{ns_late};
+            const auto future_ns = std::max(std::chrono::nanoseconds::zero(), ticks_delta);
+
+            this->system.CoreTiming().ScheduleEvent(future_ns, composition_event);
         });
+
     if (system.IsMulticore()) {
         is_running = true;
         wait_event = std::make_unique<Common::Event>();
         vsync_thread = std::make_unique<std::thread>(VSyncThread, std::ref(*this));
     } else {
-        system.CoreTiming().ScheduleEvent(frame_ticks, composition_event);
+        system.CoreTiming().ScheduleEvent(frame_ns, composition_event);
     }
 }
 
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp
index 53d27859b..09bf8c5cf 100644
--- a/src/core/memory/cheat_engine.cpp
+++ b/src/core/memory/cheat_engine.cpp
@@ -20,7 +20,7 @@
 
 namespace Core::Memory {
 
-constexpr s64 CHEAT_ENGINE_TICKS = static_cast<s64>(1000000000 / 12);
+constexpr auto CHEAT_ENGINE_NS = std::chrono::nanoseconds{1000000000 / 12};
 constexpr u32 KEYPAD_BITMASK = 0x3FFFFFF;
 
 StandardVmCallbacks::StandardVmCallbacks(Core::System& system, const CheatProcessMetadata& metadata)
@@ -191,7 +191,7 @@ void CheatEngine::Initialize() {
     event = Core::Timing::CreateEvent(
         "CheatEngine::FrameCallback::" + Common::HexToString(metadata.main_nso_build_id),
         [this](u64 userdata, s64 ns_late) { FrameCallback(userdata, ns_late); });
-    core_timing.ScheduleEvent(CHEAT_ENGINE_TICKS, event);
+    core_timing.ScheduleEvent(CHEAT_ENGINE_NS, event);
 
     metadata.process_id = system.CurrentProcess()->GetProcessID();
     metadata.title_id = system.CurrentProcess()->GetTitleID();
@@ -230,7 +230,8 @@ void CheatEngine::FrameCallback(u64 userdata, s64 ns_late) {
 
     vm.Execute(metadata);
 
-    core_timing.ScheduleEvent(CHEAT_ENGINE_TICKS - ns_late, event);
+    const auto future_ns = CHEAT_ENGINE_NS - std::chrono::nanoseconds{ns_late};
+    core_timing.ScheduleEvent(future_ns, event);
 }
 
 } // namespace Core::Memory
diff --git a/src/core/tools/freezer.cpp b/src/core/tools/freezer.cpp
index 8b0c50d11..5dc52d1c1 100644
--- a/src/core/tools/freezer.cpp
+++ b/src/core/tools/freezer.cpp
@@ -14,7 +14,7 @@
 namespace Tools {
 namespace {
 
-constexpr s64 MEMORY_FREEZER_TICKS = static_cast<s64>(1000000000 / 60);
+constexpr auto memory_freezer_ns = std::chrono::nanoseconds{1000000000 / 60};
 
 u64 MemoryReadWidth(Core::Memory::Memory& memory, u32 width, VAddr addr) {
     switch (width) {
@@ -58,7 +58,7 @@ Freezer::Freezer(Core::Timing::CoreTiming& core_timing_, Core::Memory::Memory& m
     event = Core::Timing::CreateEvent(
         "MemoryFreezer::FrameCallback",
         [this](u64 userdata, s64 ns_late) { FrameCallback(userdata, ns_late); });
-    core_timing.ScheduleEvent(MEMORY_FREEZER_TICKS, event);
+    core_timing.ScheduleEvent(memory_freezer_ns, event);
 }
 
 Freezer::~Freezer() {
@@ -68,7 +68,7 @@ Freezer::~Freezer() {
 void Freezer::SetActive(bool active) {
     if (!this->active.exchange(active)) {
         FillEntryReads();
-        core_timing.ScheduleEvent(MEMORY_FREEZER_TICKS, event);
+        core_timing.ScheduleEvent(memory_freezer_ns, event);
         LOG_DEBUG(Common_Memory, "Memory freezer activated!");
     } else {
         LOG_DEBUG(Common_Memory, "Memory freezer deactivated!");
@@ -173,7 +173,8 @@ void Freezer::FrameCallback(u64 userdata, s64 ns_late) {
         MemoryWriteWidth(memory, entry.width, entry.address, entry.value);
     }
 
-    core_timing.ScheduleEvent(MEMORY_FREEZER_TICKS - ns_late, event);
+    const auto future_ns = memory_freezer_ns - std::chrono::nanoseconds{ns_late};
+    core_timing.ScheduleEvent(future_ns, event);
 }
 
 void Freezer::FillEntryReads() {
diff --git a/src/tests/core/core_timing.cpp b/src/tests/core/core_timing.cpp
index e66db1940..4ede1bc2e 100644
--- a/src/tests/core/core_timing.cpp
+++ b/src/tests/core/core_timing.cpp
@@ -116,13 +116,16 @@ TEST_CASE("CoreTiming[BasicOrderNoPausing]", "[core]") {
 
     expected_callback = 0;
 
-    u64 start = core_timing.GetGlobalTimeNs().count();
-    u64 one_micro = 1000U;
+    const u64 start = core_timing.GetGlobalTimeNs().count();
+    const u64 one_micro = 1000U;
+
     for (std::size_t i = 0; i < events.size(); i++) {
-        u64 order = calls_order[i];
-        core_timing.ScheduleEvent(i * one_micro + 100U, events[order], CB_IDS[order]);
+        const u64 order = calls_order[i];
+        const auto future_ns = std::chrono::nanoseconds{static_cast<s64>(i * one_micro + 100)};
+        core_timing.ScheduleEvent(future_ns, events[order], CB_IDS[order]);
     }
-    u64 end = core_timing.GetGlobalTimeNs().count();
+
+    const u64 end = core_timing.GetGlobalTimeNs().count();
     const double scheduling_time = static_cast<double>(end - start);
     const double timer_time = static_cast<double>(TestTimerSpeed(core_timing));