From bef1844a51a37c1c8dc531e67069ef00821ffa9c Mon Sep 17 00:00:00 2001 From: Lioncash Date: Wed, 15 Jul 2020 19:14:21 -0400 Subject: [PATCH] core_timing: Make TimedCallback take std::chrono::nanoseconds Enforces our desired time units directly with a concrete type. --- src/audio_core/stream.cpp | 13 +++++++------ src/audio_core/stream.h | 4 ++-- src/core/core_timing.cpp | 7 ++++--- src/core/core_timing.h | 10 ++++------ src/core/hardware_interrupt_manager.cpp | 13 +++++++------ src/core/hle/kernel/kernel.cpp | 2 +- src/core/hle/kernel/server_session.cpp | 2 +- src/core/hle/kernel/time_manager.cpp | 2 +- src/core/hle/service/hid/hid.cpp | 9 ++++----- src/core/hle/service/hid/hid.h | 7 +++---- src/core/hle/service/nvflinger/nvflinger.cpp | 6 +++--- src/core/memory/cheat_engine.cpp | 13 +++++++------ src/core/memory/cheat_engine.h | 3 ++- src/core/tools/freezer.cpp | 12 ++++++------ src/core/tools/freezer.h | 3 ++- src/tests/core/core_timing.cpp | 14 ++++++++------ 16 files changed, 62 insertions(+), 58 deletions(-) diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp index abd8576e2..f80ab92e4 100644 --- a/src/audio_core/stream.cpp +++ b/src/audio_core/stream.cpp @@ -38,7 +38,7 @@ Stream::Stream(Core::Timing::CoreTiming& core_timing, u32 sample_rate, Format fo sink_stream{sink_stream}, core_timing{core_timing}, name{std::move(name_)} { release_event = Core::Timing::CreateEvent( - name, [this](u64 userdata, s64 cycles_late) { ReleaseActiveBuffer(cycles_late); }); + name, [this](u64, std::chrono::nanoseconds ns_late) { ReleaseActiveBuffer(ns_late); }); } void Stream::Play() { @@ -78,7 +78,7 @@ static void VolumeAdjustSamples(std::vector& samples, float game_volume) { } } -void Stream::PlayNextBuffer(s64 cycles_late) { +void Stream::PlayNextBuffer(std::chrono::nanoseconds ns_late) { if (!IsPlaying()) { // Ensure we are in playing state before playing the next buffer sink_stream.Flush(); @@ -103,17 +103,18 @@ void Stream::PlayNextBuffer(s64 cycles_late) { sink_stream.EnqueueSamples(GetNumChannels(), active_buffer->GetSamples()); - const auto time_stretch_delta = std::chrono::nanoseconds{ - Settings::values.enable_audio_stretching.GetValue() ? 0 : cycles_late}; + const auto time_stretch_delta = Settings::values.enable_audio_stretching.GetValue() + ? std::chrono::nanoseconds::zero() + : ns_late; const auto future_time = GetBufferReleaseNS(*active_buffer) - time_stretch_delta; core_timing.ScheduleEvent(future_time, release_event, {}); } -void Stream::ReleaseActiveBuffer(s64 cycles_late) { +void Stream::ReleaseActiveBuffer(std::chrono::nanoseconds ns_late) { ASSERT(active_buffer); released_buffers.push(std::move(active_buffer)); release_callback(); - PlayNextBuffer(cycles_late); + PlayNextBuffer(ns_late); } bool Stream::QueueBuffer(BufferPtr&& buffer) { diff --git a/src/audio_core/stream.h b/src/audio_core/stream.h index 2febd647c..6437b8591 100644 --- a/src/audio_core/stream.h +++ b/src/audio_core/stream.h @@ -91,10 +91,10 @@ public: private: /// Plays the next queued buffer in the audio stream, starting playback if necessary - void PlayNextBuffer(s64 cycles_late = 0); + void PlayNextBuffer(std::chrono::nanoseconds ns_late = {}); /// Releases the actively playing buffer, signalling that it has been completed - void ReleaseActiveBuffer(s64 cycles_late = 0); + void ReleaseActiveBuffer(std::chrono::nanoseconds ns_late = {}); /// Gets the number of core cycles when the specified buffer will be released std::chrono::nanoseconds GetBufferReleaseNS(const Buffer& buffer) const; diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index a5d084e08..b5feb3f24 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp @@ -58,7 +58,7 @@ void CoreTiming::Initialize(std::function&& on_thread_init_) { event_fifo_id = 0; shutting_down = false; ticks = 0; - const auto empty_timed_callback = [](u64, s64) {}; + const auto empty_timed_callback = [](u64, std::chrono::nanoseconds) {}; ev_lost = CreateEvent("_lost_event", empty_timed_callback); if (is_multicore) { timer_thread = std::make_unique(ThreadEntry, std::ref(*this)); @@ -195,8 +195,9 @@ std::optional CoreTiming::Advance() { event_queue.pop_back(); basic_lock.unlock(); - if (auto event_type{evt.type.lock()}) { - event_type->callback(evt.userdata, global_timer - evt.time); + if (const auto event_type{evt.type.lock()}) { + event_type->callback( + evt.userdata, std::chrono::nanoseconds{static_cast(global_timer - evt.time)}); } basic_lock.lock(); diff --git a/src/core/core_timing.h b/src/core/core_timing.h index 9b9f18daf..a21356a08 100644 --- a/src/core/core_timing.h +++ b/src/core/core_timing.h @@ -17,14 +17,12 @@ #include "common/common_types.h" #include "common/spin_lock.h" #include "common/thread.h" -#include "common/threadsafe_queue.h" #include "common/wall_clock.h" -#include "core/hardware_properties.h" namespace Core::Timing { /// A callback that may be scheduled for a particular core timing event. -using TimedCallback = std::function; +using TimedCallback = std::function; /// Contains the characteristics of a particular event. struct EventType { @@ -42,12 +40,12 @@ struct EventType { * in main CPU clock cycles. * * To schedule an event, you first have to register its type. This is where you pass in the - * callback. You then schedule events using the type id you get back. + * callback. You then schedule events using the type ID you get back. * - * The int cyclesLate that the callbacks get is how many cycles late it was. + * The s64 ns_late that the callbacks get is how many ns late it was. * So to schedule a new event on a regular basis: * inside callback: - * ScheduleEvent(periodInCycles - cyclesLate, callback, "whatever") + * ScheduleEvent(period_in_ns - ns_late, callback, "whatever") */ class CoreTiming { public: diff --git a/src/core/hardware_interrupt_manager.cpp b/src/core/hardware_interrupt_manager.cpp index e7fd71e2e..efc1030c1 100644 --- a/src/core/hardware_interrupt_manager.cpp +++ b/src/core/hardware_interrupt_manager.cpp @@ -11,12 +11,13 @@ namespace Core::Hardware { InterruptManager::InterruptManager(Core::System& system_in) : system(system_in) { - gpu_interrupt_event = Core::Timing::CreateEvent("GPUInterrupt", [this](u64 message, s64) { - auto nvdrv = system.ServiceManager().GetService("nvdrv"); - const u32 syncpt = static_cast(message >> 32); - const u32 value = static_cast(message); - nvdrv->SignalGPUInterruptSyncpt(syncpt, value); - }); + gpu_interrupt_event = + Core::Timing::CreateEvent("GPUInterrupt", [this](u64 message, std::chrono::nanoseconds) { + auto nvdrv = system.ServiceManager().GetService("nvdrv"); + const u32 syncpt = static_cast(message >> 32); + const u32 value = static_cast(message); + nvdrv->SignalGPUInterruptSyncpt(syncpt, value); + }); } InterruptManager::~InterruptManager() = default; diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 35fb270b8..22fc34b10 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -144,7 +144,7 @@ struct KernelCore::Impl { void InitializePreemption(KernelCore& kernel) { preemption_event = Core::Timing::CreateEvent( - "PreemptionCallback", [this, &kernel](u64 userdata, s64 cycles_late) { + "PreemptionCallback", [this, &kernel](u64, std::chrono::nanoseconds) { { SchedulerLock lock(kernel); global_scheduler.PreemptThreads(); diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 8c32f28b5..af22f4c33 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -34,7 +34,7 @@ ResultVal> ServerSession::Create(KernelCore& kern std::shared_ptr session{std::make_shared(kernel)}; session->request_event = Core::Timing::CreateEvent( - name, [session](u64 userdata, s64 cycles_late) { session->CompleteSyncRequest(); }); + name, [session](u64, std::chrono::nanoseconds) { session->CompleteSyncRequest(); }); session->name = std::move(name); session->parent = std::move(parent); diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp index ebb1e5568..88b01b751 100644 --- a/src/core/hle/kernel/time_manager.cpp +++ b/src/core/hle/kernel/time_manager.cpp @@ -16,7 +16,7 @@ namespace Kernel { TimeManager::TimeManager(Core::System& system_) : system{system_} { time_manager_event_type = Core::Timing::CreateEvent( - "Kernel::TimeManagerCallback", [this](u64 thread_handle, [[maybe_unused]] s64 cycles_late) { + "Kernel::TimeManagerCallback", [this](u64 thread_handle, std::chrono::nanoseconds) { SchedulerLock lock(system.Kernel()); Handle proper_handle = static_cast(thread_handle); if (cancelled_events[proper_handle]) { diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 62c942eac..680290cbd 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -76,8 +76,8 @@ IAppletResource::IAppletResource(Core::System& system) GetController(HidController::Unknown3).SetCommonHeaderOffset(0x5000); // Register update callbacks - pad_update_event = - Core::Timing::CreateEvent("HID::UpdatePadCallback", [this](u64 userdata, s64 ns_late) { + pad_update_event = Core::Timing::CreateEvent( + "HID::UpdatePadCallback", [this](u64 userdata, std::chrono::nanoseconds ns_late) { UpdateControllers(userdata, ns_late); }); @@ -108,7 +108,7 @@ void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) { rb.PushCopyObjects(shared_mem); } -void IAppletResource::UpdateControllers(u64 userdata, s64 ns_late) { +void IAppletResource::UpdateControllers(u64 userdata, std::chrono::nanoseconds ns_late) { auto& core_timing = system.CoreTiming(); const bool should_reload = Settings::values.is_device_reload_pending.exchange(false); @@ -119,8 +119,7 @@ void IAppletResource::UpdateControllers(u64 userdata, s64 ns_late) { controller->OnUpdate(core_timing, shared_mem->GetPointer(), SHARED_MEMORY_SIZE); } - const auto future_ns = pad_update_ns - std::chrono::nanoseconds{ns_late}; - core_timing.ScheduleEvent(future_ns, pad_update_event); + core_timing.ScheduleEvent(pad_update_ns - ns_late, pad_update_event); } class IActiveVibrationDeviceList final : public ServiceFramework { diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 6fb048360..c6f0a2584 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -4,10 +4,9 @@ #pragma once -#include "core/hle/service/hid/controllers/controller_base.h" -#include "core/hle/service/service.h" +#include -#include "controllers/controller_base.h" +#include "core/hle/service/hid/controllers/controller_base.h" #include "core/hle/service/service.h" namespace Core::Timing { @@ -65,7 +64,7 @@ private: } void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx); - void UpdateControllers(u64 userdata, s64 cycles_late); + void UpdateControllers(u64 userdata, std::chrono::nanoseconds ns_late); std::shared_ptr shared_mem; diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index 76672264d..789856118 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -66,13 +66,13 @@ NVFlinger::NVFlinger(Core::System& system) : system(system) { guard = std::make_shared(); // Schedule the screen composition events - composition_event = - Core::Timing::CreateEvent("ScreenComposition", [this](u64 userdata, s64 ns_late) { + composition_event = Core::Timing::CreateEvent( + "ScreenComposition", [this](u64, std::chrono::nanoseconds ns_late) { Lock(); Compose(); const auto ticks = std::chrono::nanoseconds{GetNextTicks()}; - const auto ticks_delta = ticks - std::chrono::nanoseconds{ns_late}; + const auto ticks_delta = ticks - ns_late; const auto future_ns = std::max(std::chrono::nanoseconds::zero(), ticks_delta); this->system.CoreTiming().ScheduleEvent(future_ns, composition_event); diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp index 09bf8c5cf..ced41b1fe 100644 --- a/src/core/memory/cheat_engine.cpp +++ b/src/core/memory/cheat_engine.cpp @@ -188,9 +188,11 @@ CheatEngine::~CheatEngine() { } 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); }); + event = Core::Timing::CreateEvent("CheatEngine::FrameCallback::" + + Common::HexToString(metadata.main_nso_build_id), + [this](u64 userdata, std::chrono::nanoseconds ns_late) { + FrameCallback(userdata, ns_late); + }); core_timing.ScheduleEvent(CHEAT_ENGINE_NS, event); metadata.process_id = system.CurrentProcess()->GetProcessID(); @@ -217,7 +219,7 @@ void CheatEngine::Reload(std::vector cheats) { MICROPROFILE_DEFINE(Cheat_Engine, "Add-Ons", "Cheat Engine", MP_RGB(70, 200, 70)); -void CheatEngine::FrameCallback(u64 userdata, s64 ns_late) { +void CheatEngine::FrameCallback(u64, std::chrono::nanoseconds ns_late) { if (is_pending_reload.exchange(false)) { vm.LoadProgram(cheats); } @@ -230,8 +232,7 @@ void CheatEngine::FrameCallback(u64 userdata, s64 ns_late) { vm.Execute(metadata); - const auto future_ns = CHEAT_ENGINE_NS - std::chrono::nanoseconds{ns_late}; - core_timing.ScheduleEvent(future_ns, event); + core_timing.ScheduleEvent(CHEAT_ENGINE_NS - ns_late, event); } } // namespace Core::Memory diff --git a/src/core/memory/cheat_engine.h b/src/core/memory/cheat_engine.h index 2649423f8..d4068cf84 100644 --- a/src/core/memory/cheat_engine.h +++ b/src/core/memory/cheat_engine.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include #include #include "common/common_types.h" @@ -71,7 +72,7 @@ public: void Reload(std::vector cheats); private: - void FrameCallback(u64 userdata, s64 cycles_late); + void FrameCallback(u64 userdata, std::chrono::nanoseconds ns_late); DmntCheatVm vm; CheatProcessMetadata metadata; diff --git a/src/core/tools/freezer.cpp b/src/core/tools/freezer.cpp index 5dc52d1c1..27b894b51 100644 --- a/src/core/tools/freezer.cpp +++ b/src/core/tools/freezer.cpp @@ -55,9 +55,10 @@ void MemoryWriteWidth(Core::Memory::Memory& memory, u32 width, VAddr addr, u64 v Freezer::Freezer(Core::Timing::CoreTiming& core_timing_, Core::Memory::Memory& memory_) : core_timing{core_timing_}, memory{memory_} { - event = Core::Timing::CreateEvent( - "MemoryFreezer::FrameCallback", - [this](u64 userdata, s64 ns_late) { FrameCallback(userdata, ns_late); }); + event = Core::Timing::CreateEvent("MemoryFreezer::FrameCallback", + [this](u64 userdata, std::chrono::nanoseconds ns_late) { + FrameCallback(userdata, ns_late); + }); core_timing.ScheduleEvent(memory_freezer_ns, event); } @@ -158,7 +159,7 @@ std::vector Freezer::GetEntries() const { return entries; } -void Freezer::FrameCallback(u64 userdata, s64 ns_late) { +void Freezer::FrameCallback(u64, std::chrono::nanoseconds ns_late) { if (!IsActive()) { LOG_DEBUG(Common_Memory, "Memory freezer has been deactivated, ending callback events."); return; @@ -173,8 +174,7 @@ void Freezer::FrameCallback(u64 userdata, s64 ns_late) { MemoryWriteWidth(memory, entry.width, entry.address, entry.value); } - const auto future_ns = memory_freezer_ns - std::chrono::nanoseconds{ns_late}; - core_timing.ScheduleEvent(future_ns, event); + core_timing.ScheduleEvent(memory_freezer_ns - ns_late, event); } void Freezer::FillEntryReads() { diff --git a/src/core/tools/freezer.h b/src/core/tools/freezer.h index 62fc6aa6c..8438783d5 100644 --- a/src/core/tools/freezer.h +++ b/src/core/tools/freezer.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include #include #include @@ -72,7 +73,7 @@ public: std::vector GetEntries() const; private: - void FrameCallback(u64 userdata, s64 cycles_late); + void FrameCallback(u64 userdata, std::chrono::nanoseconds ns_late); void FillEntryReads(); std::atomic_bool active{false}; diff --git a/src/tests/core/core_timing.cpp b/src/tests/core/core_timing.cpp index 4ede1bc2e..244463a47 100644 --- a/src/tests/core/core_timing.cpp +++ b/src/tests/core/core_timing.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -17,7 +18,6 @@ namespace { // Numbers are chosen randomly to make sure the correct one is given. constexpr std::array CB_IDS{{42, 144, 93, 1026, UINT64_C(0xFFFF7FFFF7FFFF)}}; -constexpr int MAX_SLICE_LENGTH = 10000; // Copied from CoreTiming internals constexpr std::array calls_order{{2, 0, 1, 4, 3}}; std::array delays{}; @@ -25,12 +25,12 @@ std::bitset callbacks_ran_flags; u64 expected_callback = 0; template -void HostCallbackTemplate(u64 userdata, s64 nanoseconds_late) { +void HostCallbackTemplate(u64 userdata, std::chrono::nanoseconds ns_late) { static_assert(IDX < CB_IDS.size(), "IDX out of range"); callbacks_ran_flags.set(IDX); REQUIRE(CB_IDS[IDX] == userdata); REQUIRE(CB_IDS[IDX] == CB_IDS[calls_order[expected_callback]]); - delays[IDX] = nanoseconds_late; + delays[IDX] = ns_late.count(); ++expected_callback; } @@ -77,10 +77,12 @@ TEST_CASE("CoreTiming[BasicOrder]", "[core]") { core_timing.SyncPause(true); - u64 one_micro = 1000U; + 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(i * one_micro + 100)}; + + core_timing.ScheduleEvent(future_ns, events[order], CB_IDS[order]); } /// test pause REQUIRE(callbacks_ran_flags.none());