Rework CoreTiming
This commit is contained in:
parent
c765d5be0b
commit
240650f6a6
13 changed files with 154 additions and 82 deletions
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -11,14 +11,16 @@
|
||||||
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,
|
||||||
|
std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> {
|
||||||
KThread* thread = reinterpret_cast<KThread*>(thread_handle);
|
KThread* thread = reinterpret_cast<KThread*>(thread_handle);
|
||||||
{
|
{
|
||||||
KScopedSchedulerLock sl(system.Kernel());
|
KScopedSchedulerLock sl(system.Kernel());
|
||||||
thread->OnTimer();
|
thread->OnTimer();
|
||||||
}
|
}
|
||||||
|
return std::nullopt;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in a new issue