diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/audio_core/stream.cpp | 2 | ||||
| -rw-r--r-- | src/audio_core/stream.h | 25 | ||||
| -rw-r--r-- | src/core/core_timing.cpp | 53 | ||||
| -rw-r--r-- | src/core/core_timing.h | 45 | ||||
| -rw-r--r-- | src/core/hardware_interrupt_manager.cpp | 13 | ||||
| -rw-r--r-- | src/core/hardware_interrupt_manager.h | 4 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 13 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 2 | ||||
| -rw-r--r-- | src/core/hle/service/hid/hid.cpp | 5 | ||||
| -rw-r--r-- | src/core/hle/service/hid/hid.h | 2 | ||||
| -rw-r--r-- | src/core/hle/service/nvflinger/nvflinger.cpp | 4 | ||||
| -rw-r--r-- | src/core/hle/service/nvflinger/nvflinger.h | 2 | ||||
| -rw-r--r-- | src/core/memory/cheat_engine.cpp | 2 | ||||
| -rw-r--r-- | src/core/memory/cheat_engine.h | 3 | ||||
| -rw-r--r-- | src/core/tools/freezer.cpp | 2 | ||||
| -rw-r--r-- | src/core/tools/freezer.h | 3 | ||||
| -rw-r--r-- | src/tests/core/core_timing.cpp | 84 |
17 files changed, 103 insertions, 161 deletions
diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp index 6a5f53a57..4ca98f8ea 100644 --- a/src/audio_core/stream.cpp +++ b/src/audio_core/stream.cpp | |||
| @@ -37,7 +37,7 @@ Stream::Stream(Core::Timing::CoreTiming& core_timing, u32 sample_rate, Format fo | |||
| 37 | : sample_rate{sample_rate}, format{format}, release_callback{std::move(release_callback)}, | 37 | : sample_rate{sample_rate}, format{format}, release_callback{std::move(release_callback)}, |
| 38 | sink_stream{sink_stream}, core_timing{core_timing}, name{std::move(name_)} { | 38 | sink_stream{sink_stream}, core_timing{core_timing}, name{std::move(name_)} { |
| 39 | 39 | ||
| 40 | release_event = core_timing.RegisterEvent( | 40 | release_event = Core::Timing::CreateEvent( |
| 41 | name, [this](u64 userdata, s64 cycles_late) { ReleaseActiveBuffer(); }); | 41 | name, [this](u64 userdata, s64 cycles_late) { ReleaseActiveBuffer(); }); |
| 42 | } | 42 | } |
| 43 | 43 | ||
diff --git a/src/audio_core/stream.h b/src/audio_core/stream.h index 8106cea43..1708a4d98 100644 --- a/src/audio_core/stream.h +++ b/src/audio_core/stream.h | |||
| @@ -98,18 +98,19 @@ private: | |||
| 98 | /// Gets the number of core cycles when the specified buffer will be released | 98 | /// Gets the number of core cycles when the specified buffer will be released |
| 99 | s64 GetBufferReleaseCycles(const Buffer& buffer) const; | 99 | s64 GetBufferReleaseCycles(const Buffer& buffer) const; |
| 100 | 100 | ||
| 101 | u32 sample_rate; ///< Sample rate of the stream | 101 | u32 sample_rate; ///< Sample rate of the stream |
| 102 | Format format; ///< Format of the stream | 102 | Format format; ///< Format of the stream |
| 103 | float game_volume = 1.0f; ///< The volume the game currently has set | 103 | float game_volume = 1.0f; ///< The volume the game currently has set |
| 104 | ReleaseCallback release_callback; ///< Buffer release callback for the stream | 104 | ReleaseCallback release_callback; ///< Buffer release callback for the stream |
| 105 | State state{State::Stopped}; ///< Playback state of the stream | 105 | State state{State::Stopped}; ///< Playback state of the stream |
| 106 | Core::Timing::EventType* release_event{}; ///< Core timing release event for the stream | 106 | std::shared_ptr<Core::Timing::EventType> |
| 107 | BufferPtr active_buffer; ///< Actively playing buffer in the stream | 107 | release_event; ///< Core timing release event for the stream |
| 108 | std::queue<BufferPtr> queued_buffers; ///< Buffers queued to be played in the stream | 108 | BufferPtr active_buffer; ///< Actively playing buffer in the stream |
| 109 | std::queue<BufferPtr> released_buffers; ///< Buffers recently released from the stream | 109 | std::queue<BufferPtr> queued_buffers; ///< Buffers queued to be played in the stream |
| 110 | SinkStream& sink_stream; ///< Output sink for the stream | 110 | std::queue<BufferPtr> released_buffers; ///< Buffers recently released from the stream |
| 111 | Core::Timing::CoreTiming& core_timing; ///< Core timing instance. | 111 | SinkStream& sink_stream; ///< Output sink for the stream |
| 112 | std::string name; ///< Name of the stream, must be unique | 112 | Core::Timing::CoreTiming& core_timing; ///< Core timing instance. |
| 113 | std::string name; ///< Name of the stream, must be unique | ||
| 113 | }; | 114 | }; |
| 114 | 115 | ||
| 115 | using StreamPtr = std::shared_ptr<Stream>; | 116 | using StreamPtr = std::shared_ptr<Stream>; |
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index 0e9570685..aa09fa453 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp | |||
| @@ -17,11 +17,15 @@ namespace Core::Timing { | |||
| 17 | 17 | ||
| 18 | constexpr int MAX_SLICE_LENGTH = 10000; | 18 | constexpr int MAX_SLICE_LENGTH = 10000; |
| 19 | 19 | ||
| 20 | std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) { | ||
| 21 | return std::make_shared<EventType>(std::move(callback), std::move(name)); | ||
| 22 | } | ||
| 23 | |||
| 20 | struct CoreTiming::Event { | 24 | struct CoreTiming::Event { |
| 21 | s64 time; | 25 | s64 time; |
| 22 | u64 fifo_order; | 26 | u64 fifo_order; |
| 23 | u64 userdata; | 27 | u64 userdata; |
| 24 | const EventType* type; | 28 | std::weak_ptr<EventType> type; |
| 25 | 29 | ||
| 26 | // Sort by time, unless the times are the same, in which case sort by | 30 | // Sort by time, unless the times are the same, in which case sort by |
| 27 | // the order added to the queue | 31 | // the order added to the queue |
| @@ -54,36 +58,15 @@ void CoreTiming::Initialize() { | |||
| 54 | event_fifo_id = 0; | 58 | event_fifo_id = 0; |
| 55 | 59 | ||
| 56 | const auto empty_timed_callback = [](u64, s64) {}; | 60 | const auto empty_timed_callback = [](u64, s64) {}; |
| 57 | ev_lost = RegisterEvent("_lost_event", empty_timed_callback); | 61 | ev_lost = CreateEvent("_lost_event", empty_timed_callback); |
| 58 | } | 62 | } |
| 59 | 63 | ||
| 60 | void CoreTiming::Shutdown() { | 64 | void CoreTiming::Shutdown() { |
| 61 | ClearPendingEvents(); | 65 | ClearPendingEvents(); |
| 62 | UnregisterAllEvents(); | ||
| 63 | } | ||
| 64 | |||
| 65 | EventType* CoreTiming::RegisterEvent(const std::string& name, TimedCallback callback) { | ||
| 66 | std::lock_guard guard{inner_mutex}; | ||
| 67 | // check for existing type with same name. | ||
| 68 | // we want event type names to remain unique so that we can use them for serialization. | ||
| 69 | ASSERT_MSG(event_types.find(name) == event_types.end(), | ||
| 70 | "CoreTiming Event \"{}\" is already registered. Events should only be registered " | ||
| 71 | "during Init to avoid breaking save states.", | ||
| 72 | name.c_str()); | ||
| 73 | |||
| 74 | auto info = event_types.emplace(name, EventType{callback, nullptr}); | ||
| 75 | EventType* event_type = &info.first->second; | ||
| 76 | event_type->name = &info.first->first; | ||
| 77 | return event_type; | ||
| 78 | } | ||
| 79 | |||
| 80 | void CoreTiming::UnregisterAllEvents() { | ||
| 81 | ASSERT_MSG(event_queue.empty(), "Cannot unregister events with events pending"); | ||
| 82 | event_types.clear(); | ||
| 83 | } | 66 | } |
| 84 | 67 | ||
| 85 | void CoreTiming::ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 userdata) { | 68 | void CoreTiming::ScheduleEvent(s64 cycles_into_future, const std::shared_ptr<EventType>& event_type, |
| 86 | ASSERT(event_type != nullptr); | 69 | u64 userdata) { |
| 87 | std::lock_guard guard{inner_mutex}; | 70 | std::lock_guard guard{inner_mutex}; |
| 88 | const s64 timeout = GetTicks() + cycles_into_future; | 71 | const s64 timeout = GetTicks() + cycles_into_future; |
| 89 | 72 | ||
| @@ -93,13 +76,15 @@ void CoreTiming::ScheduleEvent(s64 cycles_into_future, const EventType* event_ty | |||
| 93 | } | 76 | } |
| 94 | 77 | ||
| 95 | event_queue.emplace_back(Event{timeout, event_fifo_id++, userdata, event_type}); | 78 | event_queue.emplace_back(Event{timeout, event_fifo_id++, userdata, event_type}); |
| 79 | |||
| 96 | std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>()); | 80 | std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>()); |
| 97 | } | 81 | } |
| 98 | 82 | ||
| 99 | void CoreTiming::UnscheduleEvent(const EventType* event_type, u64 userdata) { | 83 | void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type, u64 userdata) { |
| 100 | std::lock_guard guard{inner_mutex}; | 84 | std::lock_guard guard{inner_mutex}; |
| 85 | |||
| 101 | const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) { | 86 | const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) { |
| 102 | return e.type == event_type && e.userdata == userdata; | 87 | return e.type.lock().get() == event_type.get() && e.userdata == userdata; |
| 103 | }); | 88 | }); |
| 104 | 89 | ||
| 105 | // Removing random items breaks the invariant so we have to re-establish it. | 90 | // Removing random items breaks the invariant so we have to re-establish it. |
| @@ -130,10 +115,12 @@ void CoreTiming::ClearPendingEvents() { | |||
| 130 | event_queue.clear(); | 115 | event_queue.clear(); |
| 131 | } | 116 | } |
| 132 | 117 | ||
| 133 | void CoreTiming::RemoveEvent(const EventType* event_type) { | 118 | void CoreTiming::RemoveEvent(const std::shared_ptr<EventType>& event_type) { |
| 134 | std::lock_guard guard{inner_mutex}; | 119 | std::lock_guard guard{inner_mutex}; |
| 135 | const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), | 120 | |
| 136 | [&](const Event& e) { return e.type == event_type; }); | 121 | const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) { |
| 122 | return e.type.lock().get() == event_type.get(); | ||
| 123 | }); | ||
| 137 | 124 | ||
| 138 | // Removing random items breaks the invariant so we have to re-establish it. | 125 | // Removing random items breaks the invariant so we have to re-establish it. |
| 139 | if (itr != event_queue.end()) { | 126 | if (itr != event_queue.end()) { |
| @@ -181,7 +168,11 @@ void CoreTiming::Advance() { | |||
| 181 | std::pop_heap(event_queue.begin(), event_queue.end(), std::greater<>()); | 168 | std::pop_heap(event_queue.begin(), event_queue.end(), std::greater<>()); |
| 182 | event_queue.pop_back(); | 169 | event_queue.pop_back(); |
| 183 | inner_mutex.unlock(); | 170 | inner_mutex.unlock(); |
| 184 | evt.type->callback(evt.userdata, global_timer - evt.time); | 171 | |
| 172 | if (auto event_type{evt.type.lock()}) { | ||
| 173 | event_type->callback(evt.userdata, global_timer - evt.time); | ||
| 174 | } | ||
| 175 | |||
| 185 | inner_mutex.lock(); | 176 | inner_mutex.lock(); |
| 186 | } | 177 | } |
| 187 | 178 | ||
diff --git a/src/core/core_timing.h b/src/core/core_timing.h index 3bb88c810..d50f4eb8a 100644 --- a/src/core/core_timing.h +++ b/src/core/core_timing.h | |||
| @@ -6,11 +6,12 @@ | |||
| 6 | 6 | ||
| 7 | #include <chrono> | 7 | #include <chrono> |
| 8 | #include <functional> | 8 | #include <functional> |
| 9 | #include <memory> | ||
| 9 | #include <mutex> | 10 | #include <mutex> |
| 10 | #include <optional> | 11 | #include <optional> |
| 11 | #include <string> | 12 | #include <string> |
| 12 | #include <unordered_map> | ||
| 13 | #include <vector> | 13 | #include <vector> |
| 14 | |||
| 14 | #include "common/common_types.h" | 15 | #include "common/common_types.h" |
| 15 | #include "common/threadsafe_queue.h" | 16 | #include "common/threadsafe_queue.h" |
| 16 | 17 | ||
| @@ -21,10 +22,13 @@ using TimedCallback = std::function<void(u64 userdata, s64 cycles_late)>; | |||
| 21 | 22 | ||
| 22 | /// Contains the characteristics of a particular event. | 23 | /// Contains the characteristics of a particular event. |
| 23 | struct EventType { | 24 | struct EventType { |
| 25 | EventType(TimedCallback&& callback, std::string&& name) | ||
| 26 | : callback{std::move(callback)}, name{std::move(name)} {} | ||
| 27 | |||
| 24 | /// The event's callback function. | 28 | /// The event's callback function. |
| 25 | TimedCallback callback; | 29 | TimedCallback callback; |
| 26 | /// A pointer to the name of the event. | 30 | /// A pointer to the name of the event. |
| 27 | const std::string* name; | 31 | const std::string name; |
| 28 | }; | 32 | }; |
| 29 | 33 | ||
| 30 | /** | 34 | /** |
| @@ -57,31 +61,17 @@ public: | |||
| 57 | /// Tears down all timing related functionality. | 61 | /// Tears down all timing related functionality. |
| 58 | void Shutdown(); | 62 | void Shutdown(); |
| 59 | 63 | ||
| 60 | /// Registers a core timing event with the given name and callback. | ||
| 61 | /// | ||
| 62 | /// @param name The name of the core timing event to register. | ||
| 63 | /// @param callback The callback to execute for the event. | ||
| 64 | /// | ||
| 65 | /// @returns An EventType instance representing the registered event. | ||
| 66 | /// | ||
| 67 | /// @pre The name of the event being registered must be unique among all | ||
| 68 | /// registered events. | ||
| 69 | /// | ||
| 70 | EventType* RegisterEvent(const std::string& name, TimedCallback callback); | ||
| 71 | |||
| 72 | /// Unregisters all registered events thus far. Note: not thread unsafe | ||
| 73 | void UnregisterAllEvents(); | ||
| 74 | |||
| 75 | /// After the first Advance, the slice lengths and the downcount will be reduced whenever an | 64 | /// After the first Advance, the slice lengths and the downcount will be reduced whenever an |
| 76 | /// event is scheduled earlier than the current values. | 65 | /// event is scheduled earlier than the current values. |
| 77 | /// | 66 | /// |
| 78 | /// Scheduling from a callback will not update the downcount until the Advance() completes. | 67 | /// Scheduling from a callback will not update the downcount until the Advance() completes. |
| 79 | void ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 userdata = 0); | 68 | void ScheduleEvent(s64 cycles_into_future, const std::shared_ptr<EventType>& event_type, |
| 69 | u64 userdata = 0); | ||
| 80 | 70 | ||
| 81 | void UnscheduleEvent(const EventType* event_type, u64 userdata); | 71 | void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, u64 userdata); |
| 82 | 72 | ||
| 83 | /// We only permit one event of each type in the queue at a time. | 73 | /// We only permit one event of each type in the queue at a time. |
| 84 | void RemoveEvent(const EventType* event_type); | 74 | void RemoveEvent(const std::shared_ptr<EventType>& event_type); |
| 85 | 75 | ||
| 86 | void ForceExceptionCheck(s64 cycles); | 76 | void ForceExceptionCheck(s64 cycles); |
| 87 | 77 | ||
| @@ -148,13 +138,18 @@ private: | |||
| 148 | std::vector<Event> event_queue; | 138 | std::vector<Event> event_queue; |
| 149 | u64 event_fifo_id = 0; | 139 | u64 event_fifo_id = 0; |
| 150 | 140 | ||
| 151 | // Stores each element separately as a linked list node so pointers to elements | 141 | std::shared_ptr<EventType> ev_lost; |
| 152 | // remain stable regardless of rehashes/resizing. | ||
| 153 | std::unordered_map<std::string, EventType> event_types; | ||
| 154 | |||
| 155 | EventType* ev_lost = nullptr; | ||
| 156 | 142 | ||
| 157 | std::mutex inner_mutex; | 143 | std::mutex inner_mutex; |
| 158 | }; | 144 | }; |
| 159 | 145 | ||
| 146 | /// Creates a core timing event with the given name and callback. | ||
| 147 | /// | ||
| 148 | /// @param name The name of the core timing event to create. | ||
| 149 | /// @param callback The callback to execute for the event. | ||
| 150 | /// | ||
| 151 | /// @returns An EventType instance representing the created event. | ||
| 152 | /// | ||
| 153 | std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback); | ||
| 154 | |||
| 160 | } // namespace Core::Timing | 155 | } // namespace Core::Timing |
diff --git a/src/core/hardware_interrupt_manager.cpp b/src/core/hardware_interrupt_manager.cpp index c2115db2d..c629d9fa1 100644 --- a/src/core/hardware_interrupt_manager.cpp +++ b/src/core/hardware_interrupt_manager.cpp | |||
| @@ -11,13 +11,12 @@ | |||
| 11 | namespace Core::Hardware { | 11 | namespace Core::Hardware { |
| 12 | 12 | ||
| 13 | InterruptManager::InterruptManager(Core::System& system_in) : system(system_in) { | 13 | InterruptManager::InterruptManager(Core::System& system_in) : system(system_in) { |
| 14 | gpu_interrupt_event = | 14 | gpu_interrupt_event = Core::Timing::CreateEvent("GPUInterrupt", [this](u64 message, s64) { |
| 15 | system.CoreTiming().RegisterEvent("GPUInterrupt", [this](u64 message, s64) { | 15 | auto nvdrv = system.ServiceManager().GetService<Service::Nvidia::NVDRV>("nvdrv"); |
| 16 | auto nvdrv = system.ServiceManager().GetService<Service::Nvidia::NVDRV>("nvdrv"); | 16 | const u32 syncpt = static_cast<u32>(message >> 32); |
| 17 | const u32 syncpt = static_cast<u32>(message >> 32); | 17 | const u32 value = static_cast<u32>(message); |
| 18 | const u32 value = static_cast<u32>(message); | 18 | nvdrv->SignalGPUInterruptSyncpt(syncpt, value); |
| 19 | nvdrv->SignalGPUInterruptSyncpt(syncpt, value); | 19 | }); |
| 20 | }); | ||
| 21 | } | 20 | } |
| 22 | 21 | ||
| 23 | InterruptManager::~InterruptManager() = default; | 22 | InterruptManager::~InterruptManager() = default; |
diff --git a/src/core/hardware_interrupt_manager.h b/src/core/hardware_interrupt_manager.h index 494db883a..5fa306ae0 100644 --- a/src/core/hardware_interrupt_manager.h +++ b/src/core/hardware_interrupt_manager.h | |||
| @@ -4,6 +4,8 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <memory> | ||
| 8 | |||
| 7 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 8 | 10 | ||
| 9 | namespace Core { | 11 | namespace Core { |
| @@ -25,7 +27,7 @@ public: | |||
| 25 | 27 | ||
| 26 | private: | 28 | private: |
| 27 | Core::System& system; | 29 | Core::System& system; |
| 28 | Core::Timing::EventType* gpu_interrupt_event{}; | 30 | std::shared_ptr<Core::Timing::EventType> gpu_interrupt_event; |
| 29 | }; | 31 | }; |
| 30 | 32 | ||
| 31 | } // namespace Core::Hardware | 33 | } // namespace Core::Hardware |
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 63ad07950..a9851113a 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -139,12 +139,12 @@ struct KernelCore::Impl { | |||
| 139 | 139 | ||
| 140 | void InitializeThreads() { | 140 | void InitializeThreads() { |
| 141 | thread_wakeup_event_type = | 141 | thread_wakeup_event_type = |
| 142 | system.CoreTiming().RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback); | 142 | Core::Timing::CreateEvent("ThreadWakeupCallback", ThreadWakeupCallback); |
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | void InitializePreemption() { | 145 | void InitializePreemption() { |
| 146 | preemption_event = system.CoreTiming().RegisterEvent( | 146 | preemption_event = |
| 147 | "PreemptionCallback", [this](u64 userdata, s64 cycles_late) { | 147 | Core::Timing::CreateEvent("PreemptionCallback", [this](u64 userdata, s64 cycles_late) { |
| 148 | global_scheduler.PreemptThreads(); | 148 | global_scheduler.PreemptThreads(); |
| 149 | s64 time_interval = Core::Timing::msToCycles(std::chrono::milliseconds(10)); | 149 | s64 time_interval = Core::Timing::msToCycles(std::chrono::milliseconds(10)); |
| 150 | system.CoreTiming().ScheduleEvent(time_interval, preemption_event); | 150 | system.CoreTiming().ScheduleEvent(time_interval, preemption_event); |
| @@ -166,8 +166,9 @@ struct KernelCore::Impl { | |||
| 166 | 166 | ||
| 167 | std::shared_ptr<ResourceLimit> system_resource_limit; | 167 | std::shared_ptr<ResourceLimit> system_resource_limit; |
| 168 | 168 | ||
| 169 | Core::Timing::EventType* thread_wakeup_event_type = nullptr; | 169 | std::shared_ptr<Core::Timing::EventType> thread_wakeup_event_type; |
| 170 | Core::Timing::EventType* preemption_event = nullptr; | 170 | std::shared_ptr<Core::Timing::EventType> preemption_event; |
| 171 | |||
| 171 | // TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future, | 172 | // TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future, |
| 172 | // allowing us to simply use a pool index or similar. | 173 | // allowing us to simply use a pool index or similar. |
| 173 | Kernel::HandleTable thread_wakeup_callback_handle_table; | 174 | Kernel::HandleTable thread_wakeup_callback_handle_table; |
| @@ -269,7 +270,7 @@ u64 KernelCore::CreateNewUserProcessID() { | |||
| 269 | return impl->next_user_process_id++; | 270 | return impl->next_user_process_id++; |
| 270 | } | 271 | } |
| 271 | 272 | ||
| 272 | Core::Timing::EventType* KernelCore::ThreadWakeupCallbackEventType() const { | 273 | const std::shared_ptr<Core::Timing::EventType>& KernelCore::ThreadWakeupCallbackEventType() const { |
| 273 | return impl->thread_wakeup_event_type; | 274 | return impl->thread_wakeup_event_type; |
| 274 | } | 275 | } |
| 275 | 276 | ||
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index c74b9078f..babb531c6 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -113,7 +113,7 @@ private: | |||
| 113 | u64 CreateNewThreadID(); | 113 | u64 CreateNewThreadID(); |
| 114 | 114 | ||
| 115 | /// Retrieves the event type used for thread wakeup callbacks. | 115 | /// Retrieves the event type used for thread wakeup callbacks. |
| 116 | Core::Timing::EventType* ThreadWakeupCallbackEventType() const; | 116 | const std::shared_ptr<Core::Timing::EventType>& ThreadWakeupCallbackEventType() const; |
| 117 | 117 | ||
| 118 | /// Provides a reference to the thread wakeup callback handle table. | 118 | /// Provides a reference to the thread wakeup callback handle table. |
| 119 | Kernel::HandleTable& ThreadWakeupCallbackHandleTable(); | 119 | Kernel::HandleTable& ThreadWakeupCallbackHandleTable(); |
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 8ef029e0f..89bf8b815 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -77,15 +77,14 @@ IAppletResource::IAppletResource(Core::System& system) | |||
| 77 | GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000); | 77 | GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000); |
| 78 | 78 | ||
| 79 | // Register update callbacks | 79 | // Register update callbacks |
| 80 | auto& core_timing = system.CoreTiming(); | ||
| 81 | pad_update_event = | 80 | pad_update_event = |
| 82 | core_timing.RegisterEvent("HID::UpdatePadCallback", [this](u64 userdata, s64 cycles_late) { | 81 | Core::Timing::CreateEvent("HID::UpdatePadCallback", [this](u64 userdata, s64 cycles_late) { |
| 83 | UpdateControllers(userdata, cycles_late); | 82 | UpdateControllers(userdata, cycles_late); |
| 84 | }); | 83 | }); |
| 85 | 84 | ||
| 86 | // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?) | 85 | // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?) |
| 87 | 86 | ||
| 88 | core_timing.ScheduleEvent(pad_update_ticks, pad_update_event); | 87 | system.CoreTiming().ScheduleEvent(pad_update_ticks, pad_update_event); |
| 89 | 88 | ||
| 90 | ReloadInputDevices(); | 89 | ReloadInputDevices(); |
| 91 | } | 90 | } |
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 923762fff..ad20f147c 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h | |||
| @@ -69,7 +69,7 @@ private: | |||
| 69 | 69 | ||
| 70 | std::shared_ptr<Kernel::SharedMemory> shared_mem; | 70 | std::shared_ptr<Kernel::SharedMemory> shared_mem; |
| 71 | 71 | ||
| 72 | Core::Timing::EventType* pad_update_event; | 72 | std::shared_ptr<Core::Timing::EventType> pad_update_event; |
| 73 | Core::System& system; | 73 | Core::System& system; |
| 74 | 74 | ||
| 75 | std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)> | 75 | std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)> |
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index cd07ab362..52623cf89 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp | |||
| @@ -37,8 +37,8 @@ NVFlinger::NVFlinger(Core::System& system) : system(system) { | |||
| 37 | displays.emplace_back(4, "Null", system); | 37 | displays.emplace_back(4, "Null", system); |
| 38 | 38 | ||
| 39 | // Schedule the screen composition events | 39 | // Schedule the screen composition events |
| 40 | composition_event = system.CoreTiming().RegisterEvent( | 40 | composition_event = |
| 41 | "ScreenComposition", [this](u64 userdata, s64 cycles_late) { | 41 | Core::Timing::CreateEvent("ScreenComposition", [this](u64 userdata, s64 cycles_late) { |
| 42 | Compose(); | 42 | Compose(); |
| 43 | const auto ticks = | 43 | const auto ticks = |
| 44 | Settings::values.force_30fps_mode ? frame_ticks_30fps : GetNextTicks(); | 44 | Settings::values.force_30fps_mode ? frame_ticks_30fps : GetNextTicks(); |
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index 9cc41f2e6..e3cc14bdc 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h | |||
| @@ -103,7 +103,7 @@ private: | |||
| 103 | u32 swap_interval = 1; | 103 | u32 swap_interval = 1; |
| 104 | 104 | ||
| 105 | /// Event that handles screen composition. | 105 | /// Event that handles screen composition. |
| 106 | Core::Timing::EventType* composition_event; | 106 | std::shared_ptr<Core::Timing::EventType> composition_event; |
| 107 | 107 | ||
| 108 | Core::System& system; | 108 | Core::System& system; |
| 109 | }; | 109 | }; |
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp index 10821d452..b73cc9fbd 100644 --- a/src/core/memory/cheat_engine.cpp +++ b/src/core/memory/cheat_engine.cpp | |||
| @@ -186,7 +186,7 @@ CheatEngine::~CheatEngine() { | |||
| 186 | } | 186 | } |
| 187 | 187 | ||
| 188 | void CheatEngine::Initialize() { | 188 | void CheatEngine::Initialize() { |
| 189 | event = core_timing.RegisterEvent( | 189 | event = Core::Timing::CreateEvent( |
| 190 | "CheatEngine::FrameCallback::" + Common::HexToString(metadata.main_nso_build_id), | 190 | "CheatEngine::FrameCallback::" + Common::HexToString(metadata.main_nso_build_id), |
| 191 | [this](u64 userdata, s64 cycles_late) { FrameCallback(userdata, cycles_late); }); | 191 | [this](u64 userdata, s64 cycles_late) { FrameCallback(userdata, cycles_late); }); |
| 192 | core_timing.ScheduleEvent(CHEAT_ENGINE_TICKS, event); | 192 | core_timing.ScheduleEvent(CHEAT_ENGINE_TICKS, event); |
diff --git a/src/core/memory/cheat_engine.h b/src/core/memory/cheat_engine.h index 0f012e9b5..e3db90dac 100644 --- a/src/core/memory/cheat_engine.h +++ b/src/core/memory/cheat_engine.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <atomic> | 7 | #include <atomic> |
| 8 | #include <memory> | ||
| 8 | #include <vector> | 9 | #include <vector> |
| 9 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 10 | #include "core/memory/dmnt_cheat_types.h" | 11 | #include "core/memory/dmnt_cheat_types.h" |
| @@ -78,7 +79,7 @@ private: | |||
| 78 | std::vector<CheatEntry> cheats; | 79 | std::vector<CheatEntry> cheats; |
| 79 | std::atomic_bool is_pending_reload{false}; | 80 | std::atomic_bool is_pending_reload{false}; |
| 80 | 81 | ||
| 81 | Core::Timing::EventType* event{}; | 82 | std::shared_ptr<Core::Timing::EventType> event; |
| 82 | Core::Timing::CoreTiming& core_timing; | 83 | Core::Timing::CoreTiming& core_timing; |
| 83 | Core::System& system; | 84 | Core::System& system; |
| 84 | }; | 85 | }; |
diff --git a/src/core/tools/freezer.cpp b/src/core/tools/freezer.cpp index 17f050068..19b531ecb 100644 --- a/src/core/tools/freezer.cpp +++ b/src/core/tools/freezer.cpp | |||
| @@ -54,7 +54,7 @@ void MemoryWriteWidth(u32 width, VAddr addr, u64 value) { | |||
| 54 | } // Anonymous namespace | 54 | } // Anonymous namespace |
| 55 | 55 | ||
| 56 | Freezer::Freezer(Core::Timing::CoreTiming& core_timing) : core_timing(core_timing) { | 56 | Freezer::Freezer(Core::Timing::CoreTiming& core_timing) : core_timing(core_timing) { |
| 57 | event = core_timing.RegisterEvent( | 57 | event = Core::Timing::CreateEvent( |
| 58 | "MemoryFreezer::FrameCallback", | 58 | "MemoryFreezer::FrameCallback", |
| 59 | [this](u64 userdata, s64 cycles_late) { FrameCallback(userdata, cycles_late); }); | 59 | [this](u64 userdata, s64 cycles_late) { FrameCallback(userdata, cycles_late); }); |
| 60 | core_timing.ScheduleEvent(MEMORY_FREEZER_TICKS, event); | 60 | core_timing.ScheduleEvent(MEMORY_FREEZER_TICKS, event); |
diff --git a/src/core/tools/freezer.h b/src/core/tools/freezer.h index b58de5472..90b1a885c 100644 --- a/src/core/tools/freezer.h +++ b/src/core/tools/freezer.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <atomic> | 7 | #include <atomic> |
| 8 | #include <memory> | ||
| 8 | #include <mutex> | 9 | #include <mutex> |
| 9 | #include <optional> | 10 | #include <optional> |
| 10 | #include <vector> | 11 | #include <vector> |
| @@ -75,7 +76,7 @@ private: | |||
| 75 | mutable std::mutex entries_mutex; | 76 | mutable std::mutex entries_mutex; |
| 76 | std::vector<Entry> entries; | 77 | std::vector<Entry> entries; |
| 77 | 78 | ||
| 78 | Core::Timing::EventType* event; | 79 | std::shared_ptr<Core::Timing::EventType> event; |
| 79 | Core::Timing::CoreTiming& core_timing; | 80 | Core::Timing::CoreTiming& core_timing; |
| 80 | }; | 81 | }; |
| 81 | 82 | ||
diff --git a/src/tests/core/core_timing.cpp b/src/tests/core/core_timing.cpp index 3443bf05e..1e3940801 100644 --- a/src/tests/core/core_timing.cpp +++ b/src/tests/core/core_timing.cpp | |||
| @@ -7,7 +7,9 @@ | |||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <bitset> | 8 | #include <bitset> |
| 9 | #include <cstdlib> | 9 | #include <cstdlib> |
| 10 | #include <memory> | ||
| 10 | #include <string> | 11 | #include <string> |
| 12 | |||
| 11 | #include "common/file_util.h" | 13 | #include "common/file_util.h" |
| 12 | #include "core/core.h" | 14 | #include "core/core.h" |
| 13 | #include "core/core_timing.h" | 15 | #include "core/core_timing.h" |
| @@ -65,11 +67,16 @@ TEST_CASE("CoreTiming[BasicOrder]", "[core]") { | |||
| 65 | ScopeInit guard; | 67 | ScopeInit guard; |
| 66 | auto& core_timing = guard.core_timing; | 68 | auto& core_timing = guard.core_timing; |
| 67 | 69 | ||
| 68 | Core::Timing::EventType* cb_a = core_timing.RegisterEvent("callbackA", CallbackTemplate<0>); | 70 | std::shared_ptr<Core::Timing::EventType> cb_a = |
| 69 | Core::Timing::EventType* cb_b = core_timing.RegisterEvent("callbackB", CallbackTemplate<1>); | 71 | Core::Timing::CreateEvent("callbackA", CallbackTemplate<0>); |
| 70 | Core::Timing::EventType* cb_c = core_timing.RegisterEvent("callbackC", CallbackTemplate<2>); | 72 | std::shared_ptr<Core::Timing::EventType> cb_b = |
| 71 | Core::Timing::EventType* cb_d = core_timing.RegisterEvent("callbackD", CallbackTemplate<3>); | 73 | Core::Timing::CreateEvent("callbackB", CallbackTemplate<1>); |
| 72 | Core::Timing::EventType* cb_e = core_timing.RegisterEvent("callbackE", CallbackTemplate<4>); | 74 | std::shared_ptr<Core::Timing::EventType> cb_c = |
| 75 | Core::Timing::CreateEvent("callbackC", CallbackTemplate<2>); | ||
| 76 | std::shared_ptr<Core::Timing::EventType> cb_d = | ||
| 77 | Core::Timing::CreateEvent("callbackD", CallbackTemplate<3>); | ||
| 78 | std::shared_ptr<Core::Timing::EventType> cb_e = | ||
| 79 | Core::Timing::CreateEvent("callbackE", CallbackTemplate<4>); | ||
| 73 | 80 | ||
| 74 | // Enter slice 0 | 81 | // Enter slice 0 |
| 75 | core_timing.ResetRun(); | 82 | core_timing.ResetRun(); |
| @@ -99,8 +106,8 @@ TEST_CASE("CoreTiming[FairSharing]", "[core]") { | |||
| 99 | ScopeInit guard; | 106 | ScopeInit guard; |
| 100 | auto& core_timing = guard.core_timing; | 107 | auto& core_timing = guard.core_timing; |
| 101 | 108 | ||
| 102 | Core::Timing::EventType* empty_callback = | 109 | std::shared_ptr<Core::Timing::EventType> empty_callback = |
| 103 | core_timing.RegisterEvent("empty_callback", EmptyCallback); | 110 | Core::Timing::CreateEvent("empty_callback", EmptyCallback); |
| 104 | 111 | ||
| 105 | callbacks_done = 0; | 112 | callbacks_done = 0; |
| 106 | u64 MAX_CALLBACKS = 10; | 113 | u64 MAX_CALLBACKS = 10; |
| @@ -133,8 +140,10 @@ TEST_CASE("Core::Timing[PredictableLateness]", "[core]") { | |||
| 133 | ScopeInit guard; | 140 | ScopeInit guard; |
| 134 | auto& core_timing = guard.core_timing; | 141 | auto& core_timing = guard.core_timing; |
| 135 | 142 | ||
| 136 | Core::Timing::EventType* cb_a = core_timing.RegisterEvent("callbackA", CallbackTemplate<0>); | 143 | std::shared_ptr<Core::Timing::EventType> cb_a = |
| 137 | Core::Timing::EventType* cb_b = core_timing.RegisterEvent("callbackB", CallbackTemplate<1>); | 144 | Core::Timing::CreateEvent("callbackA", CallbackTemplate<0>); |
| 145 | std::shared_ptr<Core::Timing::EventType> cb_b = | ||
| 146 | Core::Timing::CreateEvent("callbackB", CallbackTemplate<1>); | ||
| 138 | 147 | ||
| 139 | // Enter slice 0 | 148 | // Enter slice 0 |
| 140 | core_timing.ResetRun(); | 149 | core_timing.ResetRun(); |
| @@ -145,60 +154,3 @@ TEST_CASE("Core::Timing[PredictableLateness]", "[core]") { | |||
| 145 | AdvanceAndCheck(core_timing, 0, 0, 10, -10); // (100 - 10) | 154 | AdvanceAndCheck(core_timing, 0, 0, 10, -10); // (100 - 10) |
| 146 | AdvanceAndCheck(core_timing, 1, 1, 50, -50); | 155 | AdvanceAndCheck(core_timing, 1, 1, 50, -50); |
| 147 | } | 156 | } |
| 148 | |||
| 149 | namespace ChainSchedulingTest { | ||
| 150 | static int reschedules = 0; | ||
| 151 | |||
| 152 | static void RescheduleCallback(Core::Timing::CoreTiming& core_timing, u64 userdata, | ||
| 153 | s64 cycles_late) { | ||
| 154 | --reschedules; | ||
| 155 | REQUIRE(reschedules >= 0); | ||
| 156 | REQUIRE(lateness == cycles_late); | ||
| 157 | |||
| 158 | if (reschedules > 0) { | ||
| 159 | core_timing.ScheduleEvent(1000, reinterpret_cast<Core::Timing::EventType*>(userdata), | ||
| 160 | userdata); | ||
| 161 | } | ||
| 162 | } | ||
| 163 | } // namespace ChainSchedulingTest | ||
| 164 | |||
| 165 | TEST_CASE("CoreTiming[ChainScheduling]", "[core]") { | ||
| 166 | using namespace ChainSchedulingTest; | ||
| 167 | |||
| 168 | ScopeInit guard; | ||
| 169 | auto& core_timing = guard.core_timing; | ||
| 170 | |||
| 171 | Core::Timing::EventType* cb_a = core_timing.RegisterEvent("callbackA", CallbackTemplate<0>); | ||
| 172 | Core::Timing::EventType* cb_b = core_timing.RegisterEvent("callbackB", CallbackTemplate<1>); | ||
| 173 | Core::Timing::EventType* cb_c = core_timing.RegisterEvent("callbackC", CallbackTemplate<2>); | ||
| 174 | Core::Timing::EventType* cb_rs = core_timing.RegisterEvent( | ||
| 175 | "callbackReschedule", [&core_timing](u64 userdata, s64 cycles_late) { | ||
| 176 | RescheduleCallback(core_timing, userdata, cycles_late); | ||
| 177 | }); | ||
| 178 | |||
| 179 | // Enter slice 0 | ||
| 180 | core_timing.ResetRun(); | ||
| 181 | |||
| 182 | core_timing.ScheduleEvent(800, cb_a, CB_IDS[0]); | ||
| 183 | core_timing.ScheduleEvent(1000, cb_b, CB_IDS[1]); | ||
| 184 | core_timing.ScheduleEvent(2200, cb_c, CB_IDS[2]); | ||
| 185 | core_timing.ScheduleEvent(1000, cb_rs, reinterpret_cast<u64>(cb_rs)); | ||
| 186 | REQUIRE(800 == core_timing.GetDowncount()); | ||
| 187 | |||
| 188 | reschedules = 3; | ||
| 189 | AdvanceAndCheck(core_timing, 0, 0); // cb_a | ||
| 190 | AdvanceAndCheck(core_timing, 1, 1); // cb_b, cb_rs | ||
| 191 | REQUIRE(2 == reschedules); | ||
| 192 | |||
| 193 | core_timing.AddTicks(core_timing.GetDowncount()); | ||
| 194 | core_timing.Advance(); // cb_rs | ||
| 195 | core_timing.SwitchContext(3); | ||
| 196 | REQUIRE(1 == reschedules); | ||
| 197 | REQUIRE(200 == core_timing.GetDowncount()); | ||
| 198 | |||
| 199 | AdvanceAndCheck(core_timing, 2, 3); // cb_c | ||
| 200 | |||
| 201 | core_timing.AddTicks(core_timing.GetDowncount()); | ||
| 202 | core_timing.Advance(); // cb_rs | ||
| 203 | REQUIRE(0 == reschedules); | ||
| 204 | } | ||