mirror of
				https://git.tardis.systems/mirrors/yuzu
				synced 2025-10-31 18:54:14 +01:00 
			
		
		
		
	Merge pull request #8561 from Kelebek1/Audio-CoreTiming
Rework CoreTiming events
This commit is contained in:
		
						commit
						25e47738f7
					
				| @ -2,6 +2,7 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #include <limits> | ||||
| #include <optional> | ||||
| #include <vector> | ||||
| 
 | ||||
| #include "audio_core/audio_out.h" | ||||
| @ -88,9 +89,12 @@ AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing_, Core::Memor | ||||
|     stream = audio_out->OpenStream( | ||||
|         core_timing, params.sample_rate, AudioCommon::STREAM_NUM_CHANNELS, | ||||
|         fmt::format("AudioRenderer-Instance{}", instance_number), std::move(release_callback)); | ||||
|     process_event = Core::Timing::CreateEvent( | ||||
|         fmt::format("AudioRenderer-Instance{}-Process", instance_number), | ||||
|         [this](std::uintptr_t, std::chrono::nanoseconds) { ReleaseAndQueueBuffers(); }); | ||||
|     process_event = | ||||
|         Core::Timing::CreateEvent(fmt::format("AudioRenderer-Instance{}-Process", instance_number), | ||||
|                                   [this](std::uintptr_t, s64, std::chrono::nanoseconds) { | ||||
|                                       ReleaseAndQueueBuffers(); | ||||
|                                       return std::nullopt; | ||||
|                                   }); | ||||
|     for (s32 i = 0; i < NUM_BUFFERS; ++i) { | ||||
|         QueueMixedBuffer(i); | ||||
|     } | ||||
|  | ||||
| @ -34,9 +34,10 @@ Stream::Stream(Core::Timing::CoreTiming& core_timing_, u32 sample_rate_, Format | ||||
|                ReleaseCallback&& release_callback_, SinkStream& sink_stream_, std::string&& name_) | ||||
|     : sample_rate{sample_rate_}, format{format_}, release_callback{std::move(release_callback_)}, | ||||
|       sink_stream{sink_stream_}, core_timing{core_timing_}, name{std::move(name_)} { | ||||
|     release_event = | ||||
|         Core::Timing::CreateEvent(name, [this](std::uintptr_t, std::chrono::nanoseconds ns_late) { | ||||
|     release_event = Core::Timing::CreateEvent( | ||||
|         name, [this](std::uintptr_t, s64 time, std::chrono::nanoseconds ns_late) { | ||||
|             ReleaseActiveBuffer(ns_late); | ||||
|             return std::nullopt; | ||||
|         }); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -22,10 +22,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
 | ||||
| @ -58,7 +59,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) { | ||||
|         worker_threads.emplace_back(ThreadEntry, std::ref(*this), 0); | ||||
| @ -76,6 +78,7 @@ void CoreTiming::Shutdown() { | ||||
|         thread.join(); | ||||
|     } | ||||
|     worker_threads.clear(); | ||||
|     pause_callbacks.clear(); | ||||
|     ClearPendingEvents(); | ||||
|     has_started = false; | ||||
| } | ||||
| @ -93,6 +96,14 @@ void CoreTiming::Pause(bool is_paused_) { | ||||
|         } | ||||
|     } | ||||
|     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_) { | ||||
| @ -116,6 +127,14 @@ void CoreTiming::SyncPause(bool is_paused_) { | ||||
|             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 { | ||||
| @ -129,12 +148,30 @@ 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::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); | ||||
| 
 | ||||
|     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() { | ||||
|     global_timer = GetGlobalTimeNs().count(); | ||||
| 
 | ||||
| @ -223,14 +265,31 @@ std::optional<s64> CoreTiming::Advance() { | ||||
|         event_queue.pop_back(); | ||||
| 
 | ||||
|         if (const auto event_type{evt.type.lock()}) { | ||||
| 
 | ||||
|             event_mutex.unlock(); | ||||
| 
 | ||||
|             const s64 delay = static_cast<s64>(GetGlobalTimeNs().count() - evt.time); | ||||
|             event_type->callback(evt.user_data, std::chrono::nanoseconds{delay}); | ||||
|             const auto new_schedule_time{event_type->callback( | ||||
|                 evt.user_data, evt.time, | ||||
|                 std::chrono::nanoseconds{GetGlobalTimeNs().count() - evt.time})}; | ||||
| 
 | ||||
|             event_mutex.lock(); | ||||
|             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(); | ||||
|  | ||||
| @ -20,8 +20,9 @@ | ||||
| namespace Core::Timing { | ||||
| 
 | ||||
| /// A callback that may be scheduled for a particular core timing event.
 | ||||
| using TimedCallback = | ||||
|     std::function<void(std::uintptr_t user_data, std::chrono::nanoseconds ns_late)>; | ||||
| using TimedCallback = std::function<std::optional<std::chrono::nanoseconds>( | ||||
|     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.
 | ||||
| struct EventType { | ||||
| @ -93,7 +94,15 @@ public: | ||||
| 
 | ||||
|     /// Schedules an event in core timing
 | ||||
|     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); | ||||
| 
 | ||||
| @ -125,6 +134,9 @@ public: | ||||
|     /// Checks for events manually and returns time in nanoseconds for next event, threadsafe.
 | ||||
|     std::optional<s64> Advance(); | ||||
| 
 | ||||
|     /// Register a callback function to be called when coretiming pauses.
 | ||||
|     void RegisterPauseCallback(PauseCallback&& callback); | ||||
| 
 | ||||
| private: | ||||
|     struct Event; | ||||
| 
 | ||||
| @ -136,7 +148,7 @@ private: | ||||
| 
 | ||||
|     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.
 | ||||
|     // 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 is_multicore{}; | ||||
|     size_t pause_count{}; | ||||
|     s64 pause_end_time{}; | ||||
| 
 | ||||
|     /// Cycle timing
 | ||||
|     u64 ticks{}; | ||||
|     s64 downcount{}; | ||||
| 
 | ||||
|     std::vector<PauseCallback> pause_callbacks{}; | ||||
| }; | ||||
| 
 | ||||
| /// Creates a core timing event with the given name and callback.
 | ||||
|  | ||||
| @ -11,11 +11,14 @@ namespace Core::Hardware { | ||||
| 
 | ||||
| InterruptManager::InterruptManager(Core::System& system_in) : system(system_in) { | ||||
|     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"); | ||||
|             const u32 syncpt = static_cast<u32>(message >> 32); | ||||
|             const u32 value = static_cast<u32>(message); | ||||
|             nvdrv->SignalGPUInterruptSyncpt(syncpt, value); | ||||
|             return std::nullopt; | ||||
|         }); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -234,17 +234,18 @@ struct KernelCore::Impl { | ||||
| 
 | ||||
|     void InitializePreemption(KernelCore& kernel) { | ||||
|         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); | ||||
|                     global_scheduler_context->PreemptThreads(); | ||||
|                 } | ||||
|                 const auto time_interval = std::chrono::nanoseconds{std::chrono::milliseconds(10)}; | ||||
|                 system.CoreTiming().ScheduleEvent(time_interval, preemption_event); | ||||
|                 return std::nullopt; | ||||
|             }); | ||||
| 
 | ||||
|         const auto time_interval = std::chrono::nanoseconds{std::chrono::milliseconds(10)}; | ||||
|         system.CoreTiming().ScheduleEvent(time_interval, preemption_event); | ||||
|         system.CoreTiming().ScheduleLoopingEvent(time_interval, time_interval, preemption_event); | ||||
|     } | ||||
| 
 | ||||
|     void InitializeShutdownThreads() { | ||||
|  | ||||
| @ -11,15 +11,17 @@ | ||||
| namespace Kernel { | ||||
| 
 | ||||
| TimeManager::TimeManager(Core::System& system_) : system{system_} { | ||||
|     time_manager_event_type = | ||||
|         Core::Timing::CreateEvent("Kernel::TimeManagerCallback", | ||||
|                                   [this](std::uintptr_t thread_handle, std::chrono::nanoseconds) { | ||||
|                                       KThread* thread = reinterpret_cast<KThread*>(thread_handle); | ||||
|                                       { | ||||
|                                           KScopedSchedulerLock sl(system.Kernel()); | ||||
|                                           thread->OnTimer(); | ||||
|                                       } | ||||
|                                   }); | ||||
|     time_manager_event_type = Core::Timing::CreateEvent( | ||||
|         "Kernel::TimeManagerCallback", | ||||
|         [this](std::uintptr_t thread_handle, s64 time, | ||||
|                std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> { | ||||
|             KThread* thread = reinterpret_cast<KThread*>(thread_handle); | ||||
|             { | ||||
|                 KScopedSchedulerLock sl(system.Kernel()); | ||||
|                 thread->OnTimer(); | ||||
|             } | ||||
|             return std::nullopt; | ||||
|         }); | ||||
| } | ||||
| 
 | ||||
| void TimeManager::ScheduleTimeEvent(KThread* thread, s64 nanoseconds) { | ||||
|  | ||||
| @ -74,26 +74,34 @@ IAppletResource::IAppletResource(Core::System& system_, | ||||
|     // Register update callbacks
 | ||||
|     pad_update_event = Core::Timing::CreateEvent( | ||||
|         "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(); | ||||
|             UpdateControllers(user_data, ns_late); | ||||
|             return std::nullopt; | ||||
|         }); | ||||
|     mouse_keyboard_update_event = Core::Timing::CreateEvent( | ||||
|         "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(); | ||||
|             UpdateMouseKeyboard(user_data, ns_late); | ||||
|             return std::nullopt; | ||||
|         }); | ||||
|     motion_update_event = Core::Timing::CreateEvent( | ||||
|         "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(); | ||||
|             UpdateMotion(user_data, ns_late); | ||||
|             return std::nullopt; | ||||
|         }); | ||||
| 
 | ||||
|     system.CoreTiming().ScheduleEvent(pad_update_ns, pad_update_event); | ||||
|     system.CoreTiming().ScheduleEvent(mouse_keyboard_update_ns, mouse_keyboard_update_event); | ||||
|     system.CoreTiming().ScheduleEvent(motion_update_ns, motion_update_event); | ||||
|     system.CoreTiming().ScheduleLoopingEvent(pad_update_ns, pad_update_ns, pad_update_event); | ||||
|     system.CoreTiming().ScheduleLoopingEvent(mouse_keyboard_update_ns, mouse_keyboard_update_ns, | ||||
|                                              mouse_keyboard_update_event); | ||||
|     system.CoreTiming().ScheduleLoopingEvent(motion_update_ns, motion_update_ns, | ||||
|                                              motion_update_event); | ||||
| 
 | ||||
|     system.HIDCore().ReloadInputDevices(); | ||||
| } | ||||
| @ -135,13 +143,6 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data, | ||||
|         } | ||||
|         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, | ||||
| @ -150,26 +151,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::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) { | ||||
|     auto& core_timing = system.CoreTiming(); | ||||
| 
 | ||||
|     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> { | ||||
|  | ||||
| @ -50,12 +50,15 @@ HidBus::HidBus(Core::System& system_) | ||||
|     // Register update callbacks
 | ||||
|     hidbus_update_event = Core::Timing::CreateEvent( | ||||
|         "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(); | ||||
|             UpdateHidbus(user_data, ns_late); | ||||
|             return std::nullopt; | ||||
|         }); | ||||
| 
 | ||||
|     system_.CoreTiming().ScheduleEvent(hidbus_update_ns, hidbus_update_event); | ||||
|     system_.CoreTiming().ScheduleLoopingEvent(hidbus_update_ns, hidbus_update_ns, | ||||
|                                               hidbus_update_event); | ||||
| } | ||||
| 
 | ||||
| HidBus::~HidBus() { | ||||
| @ -63,8 +66,6 @@ HidBus::~HidBus() { | ||||
| } | ||||
| 
 | ||||
| void HidBus::UpdateHidbus(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { | ||||
|     auto& core_timing = system.CoreTiming(); | ||||
| 
 | ||||
|     if (is_hidbus_enabled) { | ||||
|         for (std::size_t i = 0; i < devices.size(); ++i) { | ||||
|             if (!devices[i].is_device_initializated) { | ||||
| @ -82,13 +83,6 @@ void HidBus::UpdateHidbus(std::uintptr_t user_data, std::chrono::nanoseconds ns_ | ||||
|                         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 { | ||||
|  | ||||
| @ -67,21 +67,20 @@ NVFlinger::NVFlinger(Core::System& system_, HosBinderDriverServer& hos_binder_dr | ||||
| 
 | ||||
|     // Schedule the screen composition events
 | ||||
|     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(); | ||||
|             Compose(); | ||||
| 
 | ||||
|             const auto ticks = std::chrono::nanoseconds{GetNextTicks()}; | ||||
|             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); | ||||
|             return std::max(std::chrono::nanoseconds::zero(), | ||||
|                             std::chrono::nanoseconds(GetNextTicks()) - ns_late); | ||||
|         }); | ||||
| 
 | ||||
|     if (system.IsMulticore()) { | ||||
|         vsync_thread = std::jthread([this](std::stop_token token) { SplitVSync(token); }); | ||||
|     } else { | ||||
|         system.CoreTiming().ScheduleEvent(frame_ns, composition_event); | ||||
|         system.CoreTiming().ScheduleLoopingEvent(frame_ns, frame_ns, composition_event); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -184,10 +184,12 @@ CheatEngine::~CheatEngine() { | ||||
| void CheatEngine::Initialize() { | ||||
|     event = Core::Timing::CreateEvent( | ||||
|         "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); | ||||
|             return std::nullopt; | ||||
|         }); | ||||
|     core_timing.ScheduleEvent(CHEAT_ENGINE_NS, event); | ||||
|     core_timing.ScheduleLoopingEvent(CHEAT_ENGINE_NS, CHEAT_ENGINE_NS, event); | ||||
| 
 | ||||
|     metadata.process_id = system.CurrentProcess()->GetProcessID(); | ||||
|     metadata.title_id = system.GetCurrentProcessProgramID(); | ||||
| @ -237,8 +239,6 @@ void CheatEngine::FrameCallback(std::uintptr_t, std::chrono::nanoseconds ns_late | ||||
|     MICROPROFILE_SCOPE(Cheat_Engine); | ||||
| 
 | ||||
|     vm.Execute(metadata); | ||||
| 
 | ||||
|     core_timing.ScheduleEvent(CHEAT_ENGINE_NS - ns_late, event); | ||||
| } | ||||
| 
 | ||||
| } // namespace Core::Memory
 | ||||
|  | ||||
| @ -53,8 +53,10 @@ Freezer::Freezer(Core::Timing::CoreTiming& core_timing_, Core::Memory::Memory& m | ||||
|     : core_timing{core_timing_}, memory{memory_} { | ||||
|     event = Core::Timing::CreateEvent( | ||||
|         "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); | ||||
|             return std::nullopt; | ||||
|         }); | ||||
|     core_timing.ScheduleEvent(memory_freezer_ns, event); | ||||
| } | ||||
|  | ||||
| @ -9,6 +9,7 @@ | ||||
| #include <cstdlib> | ||||
| #include <memory> | ||||
| #include <mutex> | ||||
| #include <optional> | ||||
| #include <string> | ||||
| 
 | ||||
| #include "core/core.h" | ||||
| @ -25,13 +26,15 @@ u64 expected_callback = 0; | ||||
| std::mutex control_mutex; | ||||
| 
 | ||||
| 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); | ||||
|     static_assert(IDX < CB_IDS.size(), "IDX out of range"); | ||||
|     callbacks_ran_flags.set(IDX); | ||||
|     REQUIRE(CB_IDS[IDX] == user_data); | ||||
|     delays[IDX] = ns_late.count(); | ||||
|     ++expected_callback; | ||||
|     return std::nullopt; | ||||
| } | ||||
| 
 | ||||
| struct ScopeInit final { | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user