Rework CoreTiming

This commit is contained in:
Kelebek1 2022-07-10 06:59:40 +01:00
parent c765d5be0b
commit 240650f6a6
13 changed files with 154 additions and 82 deletions

View file

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <limits> #include <limits>
#include <optional>
#include <vector> #include <vector>
#include "audio_core/audio_out.h" #include "audio_core/audio_out.h"
@ -88,9 +89,12 @@ AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing_, Core::Memor
stream = audio_out->OpenStream( stream = audio_out->OpenStream(
core_timing, params.sample_rate, AudioCommon::STREAM_NUM_CHANNELS, core_timing, params.sample_rate, AudioCommon::STREAM_NUM_CHANNELS,
fmt::format("AudioRenderer-Instance{}", instance_number), std::move(release_callback)); fmt::format("AudioRenderer-Instance{}", instance_number), std::move(release_callback));
process_event = Core::Timing::CreateEvent( process_event =
fmt::format("AudioRenderer-Instance{}-Process", instance_number), Core::Timing::CreateEvent(fmt::format("AudioRenderer-Instance{}-Process", instance_number),
[this](std::uintptr_t, std::chrono::nanoseconds) { ReleaseAndQueueBuffers(); }); [this](std::uintptr_t, s64, std::chrono::nanoseconds) {
ReleaseAndQueueBuffers();
return std::nullopt;
});
for (s32 i = 0; i < NUM_BUFFERS; ++i) { for (s32 i = 0; i < NUM_BUFFERS; ++i) {
QueueMixedBuffer(i); QueueMixedBuffer(i);
} }

View file

@ -34,9 +34,10 @@ Stream::Stream(Core::Timing::CoreTiming& core_timing_, u32 sample_rate_, Format
ReleaseCallback&& release_callback_, SinkStream& sink_stream_, std::string&& name_) ReleaseCallback&& release_callback_, SinkStream& sink_stream_, std::string&& name_)
: sample_rate{sample_rate_}, format{format_}, release_callback{std::move(release_callback_)}, : sample_rate{sample_rate_}, format{format_}, release_callback{std::move(release_callback_)},
sink_stream{sink_stream_}, core_timing{core_timing_}, name{std::move(name_)} { sink_stream{sink_stream_}, core_timing{core_timing_}, name{std::move(name_)} {
release_event = release_event = Core::Timing::CreateEvent(
Core::Timing::CreateEvent(name, [this](std::uintptr_t, std::chrono::nanoseconds ns_late) { name, [this](std::uintptr_t, s64 time, std::chrono::nanoseconds ns_late) {
ReleaseActiveBuffer(ns_late); ReleaseActiveBuffer(ns_late);
return std::nullopt;
}); });
} }

View file

@ -22,10 +22,11 @@ std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callbac
} }
struct CoreTiming::Event { struct CoreTiming::Event {
u64 time; s64 time;
u64 fifo_order; u64 fifo_order;
std::uintptr_t user_data; std::uintptr_t user_data;
std::weak_ptr<EventType> type; std::weak_ptr<EventType> type;
s64 reschedule_time;
// Sort by time, unless the times are the same, in which case sort by // Sort by time, unless the times are the same, in which case sort by
// the order added to the queue // the order added to the queue
@ -58,7 +59,8 @@ void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) {
event_fifo_id = 0; event_fifo_id = 0;
shutting_down = false; shutting_down = false;
ticks = 0; 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); ev_lost = CreateEvent("_lost_event", empty_timed_callback);
if (is_multicore) { if (is_multicore) {
worker_threads.emplace_back(ThreadEntry, std::ref(*this), 0); worker_threads.emplace_back(ThreadEntry, std::ref(*this), 0);
@ -76,6 +78,7 @@ void CoreTiming::Shutdown() {
thread.join(); thread.join();
} }
worker_threads.clear(); worker_threads.clear();
pause_callbacks.clear();
ClearPendingEvents(); ClearPendingEvents();
has_started = false; has_started = false;
} }
@ -93,6 +96,14 @@ void CoreTiming::Pause(bool is_paused_) {
} }
} }
paused_state.store(is_paused_, std::memory_order_relaxed); paused_state.store(is_paused_, std::memory_order_relaxed);
if (!is_paused_) {
pause_end_time = GetGlobalTimeNs().count();
}
for (auto& cb : pause_callbacks) {
cb(is_paused_);
}
} }
void CoreTiming::SyncPause(bool is_paused_) { void CoreTiming::SyncPause(bool is_paused_) {
@ -116,6 +127,14 @@ void CoreTiming::SyncPause(bool is_paused_) {
wait_signal_cv.wait(main_lock, [this] { return pause_count == 0; }); wait_signal_cv.wait(main_lock, [this] { return pause_count == 0; });
} }
} }
if (!is_paused_) {
pause_end_time = GetGlobalTimeNs().count();
}
for (auto& cb : pause_callbacks) {
cb(is_paused_);
}
} }
bool CoreTiming::IsRunning() const { bool CoreTiming::IsRunning() const {
@ -129,12 +148,30 @@ bool CoreTiming::HasPendingEvents() const {
void CoreTiming::ScheduleEvent(std::chrono::nanoseconds ns_into_future, void CoreTiming::ScheduleEvent(std::chrono::nanoseconds ns_into_future,
const std::shared_ptr<EventType>& event_type, const std::shared_ptr<EventType>& event_type,
std::uintptr_t user_data) { std::uintptr_t user_data, bool absolute_time) {
std::unique_lock main_lock(event_mutex); std::unique_lock main_lock(event_mutex);
const u64 timeout = static_cast<u64>((GetGlobalTimeNs() + ns_into_future).count()); const auto next_time{absolute_time ? ns_into_future : GetGlobalTimeNs() + ns_into_future};
event_queue.emplace_back(Event{timeout, event_fifo_id++, user_data, event_type}); event_queue.emplace_back(Event{next_time.count(), event_fifo_id++, user_data, event_type, 0});
pending_events.fetch_add(1, std::memory_order_relaxed);
std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
if (is_multicore) {
event_cv.notify_one();
}
}
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::unique_lock main_lock(event_mutex);
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()});
pending_events.fetch_add(1, std::memory_order_relaxed); pending_events.fetch_add(1, std::memory_order_relaxed);
std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>()); 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) {
} }
} }
void CoreTiming::RegisterPauseCallback(PauseCallback&& callback) {
std::unique_lock main_lock(event_mutex);
pause_callbacks.emplace_back(std::move(callback));
}
std::optional<s64> CoreTiming::Advance() { std::optional<s64> CoreTiming::Advance() {
global_timer = GetGlobalTimeNs().count(); global_timer = GetGlobalTimeNs().count();
@ -223,14 +265,31 @@ std::optional<s64> CoreTiming::Advance() {
event_queue.pop_back(); event_queue.pop_back();
if (const auto event_type{evt.type.lock()}) { if (const auto event_type{evt.type.lock()}) {
event_mutex.unlock(); event_mutex.unlock();
const s64 delay = static_cast<s64>(GetGlobalTimeNs().count() - evt.time); const auto new_schedule_time{event_type->callback(
event_type->callback(evt.user_data, std::chrono::nanoseconds{delay}); evt.user_data, evt.time,
std::chrono::nanoseconds{GetGlobalTimeNs().count() - evt.time})};
event_mutex.lock(); event_mutex.lock();
pending_events.fetch_sub(1, std::memory_order_relaxed); pending_events.fetch_sub(1, std::memory_order_relaxed);
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});
pending_events.fetch_add(1, std::memory_order_relaxed);
std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
}
} }
global_timer = GetGlobalTimeNs().count(); global_timer = GetGlobalTimeNs().count();

View file

@ -20,8 +20,9 @@
namespace Core::Timing { namespace Core::Timing {
/// A callback that may be scheduled for a particular core timing event. /// A callback that may be scheduled for a particular core timing event.
using TimedCallback = using TimedCallback = std::function<std::optional<std::chrono::nanoseconds>(
std::function<void(std::uintptr_t user_data, std::chrono::nanoseconds ns_late)>; std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)>;
using PauseCallback = std::function<void(bool paused)>;
/// Contains the characteristics of a particular event. /// Contains the characteristics of a particular event.
struct EventType { struct EventType {
@ -93,7 +94,15 @@ public:
/// Schedules an event in core timing /// Schedules an event in core timing
void ScheduleEvent(std::chrono::nanoseconds ns_into_future, void ScheduleEvent(std::chrono::nanoseconds ns_into_future,
const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data = 0); const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data = 0,
bool absolute_time = false);
/// Schedules an event which will automatically re-schedule itself with the given time, until
/// unscheduled
void ScheduleLoopingEvent(std::chrono::nanoseconds start_time,
std::chrono::nanoseconds resched_time,
const std::shared_ptr<EventType>& event_type,
std::uintptr_t user_data = 0, bool absolute_time = false);
void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data); void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data);
@ -125,6 +134,9 @@ public:
/// Checks for events manually and returns time in nanoseconds for next event, threadsafe. /// Checks for events manually and returns time in nanoseconds for next event, threadsafe.
std::optional<s64> Advance(); std::optional<s64> Advance();
/// Register a callback function to be called when coretiming pauses.
void RegisterPauseCallback(PauseCallback&& callback);
private: private:
struct Event; struct Event;
@ -136,7 +148,7 @@ private:
std::unique_ptr<Common::WallClock> clock; std::unique_ptr<Common::WallClock> clock;
u64 global_timer = 0; s64 global_timer = 0;
// The queue is a min-heap using std::make_heap/push_heap/pop_heap. // The queue is a min-heap using std::make_heap/push_heap/pop_heap.
// We don't use std::priority_queue because we need to be able to serialize, unserialize and // We don't use std::priority_queue because we need to be able to serialize, unserialize and
@ -162,10 +174,13 @@ private:
bool shutting_down{}; bool shutting_down{};
bool is_multicore{}; bool is_multicore{};
size_t pause_count{}; size_t pause_count{};
s64 pause_end_time{};
/// Cycle timing /// Cycle timing
u64 ticks{}; u64 ticks{};
s64 downcount{}; s64 downcount{};
std::vector<PauseCallback> pause_callbacks{};
}; };
/// Creates a core timing event with the given name and callback. /// Creates a core timing event with the given name and callback.

View file

@ -11,11 +11,14 @@ namespace Core::Hardware {
InterruptManager::InterruptManager(Core::System& system_in) : system(system_in) { InterruptManager::InterruptManager(Core::System& system_in) : system(system_in) {
gpu_interrupt_event = Core::Timing::CreateEvent( gpu_interrupt_event = Core::Timing::CreateEvent(
"GPUInterrupt", [this](std::uintptr_t message, std::chrono::nanoseconds) { "GPUInterrupt",
[this](std::uintptr_t message, u64 time,
std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> {
auto nvdrv = system.ServiceManager().GetService<Service::Nvidia::NVDRV>("nvdrv"); auto nvdrv = system.ServiceManager().GetService<Service::Nvidia::NVDRV>("nvdrv");
const u32 syncpt = static_cast<u32>(message >> 32); const u32 syncpt = static_cast<u32>(message >> 32);
const u32 value = static_cast<u32>(message); const u32 value = static_cast<u32>(message);
nvdrv->SignalGPUInterruptSyncpt(syncpt, value); nvdrv->SignalGPUInterruptSyncpt(syncpt, value);
return std::nullopt;
}); });
} }

View file

@ -234,17 +234,19 @@ struct KernelCore::Impl {
void InitializePreemption(KernelCore& kernel) { void InitializePreemption(KernelCore& kernel) {
preemption_event = Core::Timing::CreateEvent( preemption_event = Core::Timing::CreateEvent(
"PreemptionCallback", [this, &kernel](std::uintptr_t, std::chrono::nanoseconds) { "PreemptionCallback",
[this, &kernel](std::uintptr_t, s64 time,
std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> {
{ {
KScopedSchedulerLock lock(kernel); KScopedSchedulerLock lock(kernel);
global_scheduler_context->PreemptThreads(); global_scheduler_context->PreemptThreads();
} }
const auto time_interval = std::chrono::nanoseconds{std::chrono::milliseconds(10)}; return std::nullopt;
system.CoreTiming().ScheduleEvent(time_interval, preemption_event);
}); });
const auto time_interval = std::chrono::nanoseconds{std::chrono::milliseconds(10)}; const auto time_interval = std::chrono::nanoseconds{std::chrono::milliseconds(10)};
system.CoreTiming().ScheduleEvent(time_interval, preemption_event); system.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0), time_interval,
preemption_event);
} }
void InitializeShutdownThreads() { void InitializeShutdownThreads() {

View file

@ -11,15 +11,17 @@
namespace Kernel { namespace Kernel {
TimeManager::TimeManager(Core::System& system_) : system{system_} { TimeManager::TimeManager(Core::System& system_) : system{system_} {
time_manager_event_type = time_manager_event_type = Core::Timing::CreateEvent(
Core::Timing::CreateEvent("Kernel::TimeManagerCallback", "Kernel::TimeManagerCallback",
[this](std::uintptr_t thread_handle, std::chrono::nanoseconds) { [this](std::uintptr_t thread_handle, s64 time,
KThread* thread = reinterpret_cast<KThread*>(thread_handle); std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> {
{ KThread* thread = reinterpret_cast<KThread*>(thread_handle);
KScopedSchedulerLock sl(system.Kernel()); {
thread->OnTimer(); KScopedSchedulerLock sl(system.Kernel());
} thread->OnTimer();
}); }
return std::nullopt;
});
} }
void TimeManager::ScheduleTimeEvent(KThread* thread, s64 nanoseconds) { void TimeManager::ScheduleTimeEvent(KThread* thread, s64 nanoseconds) {

View file

@ -74,26 +74,35 @@ IAppletResource::IAppletResource(Core::System& system_,
// Register update callbacks // Register update callbacks
pad_update_event = Core::Timing::CreateEvent( pad_update_event = Core::Timing::CreateEvent(
"HID::UpdatePadCallback", "HID::UpdatePadCallback",
[this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { [this](std::uintptr_t user_data, s64 time,
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
const auto guard = LockService(); const auto guard = LockService();
UpdateControllers(user_data, ns_late); UpdateControllers(user_data, ns_late);
return std::nullopt;
}); });
mouse_keyboard_update_event = Core::Timing::CreateEvent( mouse_keyboard_update_event = Core::Timing::CreateEvent(
"HID::UpdateMouseKeyboardCallback", "HID::UpdateMouseKeyboardCallback",
[this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { [this](std::uintptr_t user_data, s64 time,
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
const auto guard = LockService(); const auto guard = LockService();
UpdateMouseKeyboard(user_data, ns_late); UpdateMouseKeyboard(user_data, ns_late);
return std::nullopt;
}); });
motion_update_event = Core::Timing::CreateEvent( motion_update_event = Core::Timing::CreateEvent(
"HID::UpdateMotionCallback", "HID::UpdateMotionCallback",
[this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { [this](std::uintptr_t user_data, s64 time,
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
const auto guard = LockService(); const auto guard = LockService();
UpdateMotion(user_data, ns_late); UpdateMotion(user_data, ns_late);
return std::nullopt;
}); });
system.CoreTiming().ScheduleEvent(pad_update_ns, pad_update_event); system.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0), pad_update_ns,
system.CoreTiming().ScheduleEvent(mouse_keyboard_update_ns, mouse_keyboard_update_event); pad_update_event);
system.CoreTiming().ScheduleEvent(motion_update_ns, motion_update_event); system.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0), mouse_keyboard_update_ns,
mouse_keyboard_update_event);
system.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0), motion_update_ns,
motion_update_event);
system.HIDCore().ReloadInputDevices(); system.HIDCore().ReloadInputDevices();
} }
@ -135,13 +144,6 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data,
} }
controller->OnUpdate(core_timing); controller->OnUpdate(core_timing);
} }
// If ns_late is higher than the update rate ignore the delay
if (ns_late > pad_update_ns) {
ns_late = {};
}
core_timing.ScheduleEvent(pad_update_ns - ns_late, pad_update_event);
} }
void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data, void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data,
@ -150,26 +152,12 @@ void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data,
controllers[static_cast<size_t>(HidController::Mouse)]->OnUpdate(core_timing); controllers[static_cast<size_t>(HidController::Mouse)]->OnUpdate(core_timing);
controllers[static_cast<size_t>(HidController::Keyboard)]->OnUpdate(core_timing); controllers[static_cast<size_t>(HidController::Keyboard)]->OnUpdate(core_timing);
// If ns_late is higher than the update rate ignore the delay
if (ns_late > mouse_keyboard_update_ns) {
ns_late = {};
}
core_timing.ScheduleEvent(mouse_keyboard_update_ns - ns_late, mouse_keyboard_update_event);
} }
void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
auto& core_timing = system.CoreTiming(); auto& core_timing = system.CoreTiming();
controllers[static_cast<size_t>(HidController::NPad)]->OnMotionUpdate(core_timing); controllers[static_cast<size_t>(HidController::NPad)]->OnMotionUpdate(core_timing);
// If ns_late is higher than the update rate ignore the delay
if (ns_late > motion_update_ns) {
ns_late = {};
}
core_timing.ScheduleEvent(motion_update_ns - ns_late, motion_update_event);
} }
class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> { class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> {

View file

@ -50,12 +50,15 @@ HidBus::HidBus(Core::System& system_)
// Register update callbacks // Register update callbacks
hidbus_update_event = Core::Timing::CreateEvent( hidbus_update_event = Core::Timing::CreateEvent(
"Hidbus::UpdateCallback", "Hidbus::UpdateCallback",
[this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { [this](std::uintptr_t user_data, s64 time,
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
const auto guard = LockService(); const auto guard = LockService();
UpdateHidbus(user_data, ns_late); UpdateHidbus(user_data, ns_late);
return std::nullopt;
}); });
system_.CoreTiming().ScheduleEvent(hidbus_update_ns, hidbus_update_event); system_.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0), hidbus_update_ns,
hidbus_update_event);
} }
HidBus::~HidBus() { HidBus::~HidBus() {
@ -63,8 +66,6 @@ HidBus::~HidBus() {
} }
void HidBus::UpdateHidbus(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { void HidBus::UpdateHidbus(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
auto& core_timing = system.CoreTiming();
if (is_hidbus_enabled) { if (is_hidbus_enabled) {
for (std::size_t i = 0; i < devices.size(); ++i) { for (std::size_t i = 0; i < devices.size(); ++i) {
if (!devices[i].is_device_initializated) { if (!devices[i].is_device_initializated) {
@ -82,13 +83,6 @@ void HidBus::UpdateHidbus(std::uintptr_t user_data, std::chrono::nanoseconds ns_
sizeof(HidbusStatusManagerEntry)); sizeof(HidbusStatusManagerEntry));
} }
} }
// If ns_late is higher than the update rate ignore the delay
if (ns_late > hidbus_update_ns) {
ns_late = {};
}
core_timing.ScheduleEvent(hidbus_update_ns - ns_late, hidbus_update_event);
} }
std::optional<std::size_t> HidBus::GetDeviceIndexFromHandle(BusHandle handle) const { std::optional<std::size_t> HidBus::GetDeviceIndexFromHandle(BusHandle handle) const {

View file

@ -67,21 +67,20 @@ NVFlinger::NVFlinger(Core::System& system_, HosBinderDriverServer& hos_binder_dr
// Schedule the screen composition events // Schedule the screen composition events
composition_event = Core::Timing::CreateEvent( composition_event = Core::Timing::CreateEvent(
"ScreenComposition", [this](std::uintptr_t, std::chrono::nanoseconds ns_late) { "ScreenComposition",
[this](std::uintptr_t, s64 time,
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
const auto lock_guard = Lock(); const auto lock_guard = Lock();
Compose(); Compose();
const auto ticks = std::chrono::nanoseconds{GetNextTicks()}; return std::chrono::nanoseconds(GetNextTicks()) - 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);
}); });
if (system.IsMulticore()) { if (system.IsMulticore()) {
vsync_thread = std::jthread([this](std::stop_token token) { SplitVSync(token); }); vsync_thread = std::jthread([this](std::stop_token token) { SplitVSync(token); });
} else { } else {
system.CoreTiming().ScheduleEvent(frame_ns, composition_event); system.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0), frame_ns,
composition_event);
} }
} }

View file

@ -184,10 +184,12 @@ CheatEngine::~CheatEngine() {
void CheatEngine::Initialize() { void CheatEngine::Initialize() {
event = Core::Timing::CreateEvent( event = Core::Timing::CreateEvent(
"CheatEngine::FrameCallback::" + Common::HexToString(metadata.main_nso_build_id), "CheatEngine::FrameCallback::" + Common::HexToString(metadata.main_nso_build_id),
[this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { [this](std::uintptr_t user_data, s64 time,
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
FrameCallback(user_data, ns_late); FrameCallback(user_data, ns_late);
return std::nullopt;
}); });
core_timing.ScheduleEvent(CHEAT_ENGINE_NS, event); core_timing.ScheduleLoopingEvent(std::chrono::nanoseconds(0), CHEAT_ENGINE_NS, event);
metadata.process_id = system.CurrentProcess()->GetProcessID(); metadata.process_id = system.CurrentProcess()->GetProcessID();
metadata.title_id = system.GetCurrentProcessProgramID(); metadata.title_id = system.GetCurrentProcessProgramID();
@ -237,8 +239,6 @@ void CheatEngine::FrameCallback(std::uintptr_t, std::chrono::nanoseconds ns_late
MICROPROFILE_SCOPE(Cheat_Engine); MICROPROFILE_SCOPE(Cheat_Engine);
vm.Execute(metadata); vm.Execute(metadata);
core_timing.ScheduleEvent(CHEAT_ENGINE_NS - ns_late, event);
} }
} // namespace Core::Memory } // namespace Core::Memory

View file

@ -53,8 +53,10 @@ Freezer::Freezer(Core::Timing::CoreTiming& core_timing_, Core::Memory::Memory& m
: core_timing{core_timing_}, memory{memory_} { : core_timing{core_timing_}, memory{memory_} {
event = Core::Timing::CreateEvent( event = Core::Timing::CreateEvent(
"MemoryFreezer::FrameCallback", "MemoryFreezer::FrameCallback",
[this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { [this](std::uintptr_t user_data, s64 time,
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
FrameCallback(user_data, ns_late); FrameCallback(user_data, ns_late);
return std::nullopt;
}); });
core_timing.ScheduleEvent(memory_freezer_ns, event); core_timing.ScheduleEvent(memory_freezer_ns, event);
} }

View file

@ -9,6 +9,7 @@
#include <cstdlib> #include <cstdlib>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <optional>
#include <string> #include <string>
#include "core/core.h" #include "core/core.h"
@ -25,13 +26,15 @@ u64 expected_callback = 0;
std::mutex control_mutex; std::mutex control_mutex;
template <unsigned int IDX> template <unsigned int IDX>
void HostCallbackTemplate(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { std::optional<std::chrono::nanoseconds> HostCallbackTemplate(std::uintptr_t user_data, s64 time,
std::chrono::nanoseconds ns_late) {
std::unique_lock<std::mutex> lk(control_mutex); std::unique_lock<std::mutex> lk(control_mutex);
static_assert(IDX < CB_IDS.size(), "IDX out of range"); static_assert(IDX < CB_IDS.size(), "IDX out of range");
callbacks_ran_flags.set(IDX); callbacks_ran_flags.set(IDX);
REQUIRE(CB_IDS[IDX] == user_data); REQUIRE(CB_IDS[IDX] == user_data);
delays[IDX] = ns_late.count(); delays[IDX] = ns_late.count();
++expected_callback; ++expected_callback;
return std::nullopt;
} }
struct ScopeInit final { struct ScopeInit final {