mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu-mainline.git
				synced 2025-03-21 01:53:15 +00:00 
			
		
		
		
	core_timing: Use better reference tracking for EventType. (#3159)
* core_timing: Use better reference tracking for EventType. - Moves ownership of the event to the caller, ensuring we don't fire events for destroyed objects. - Removes need for unique names - we won't be using this for save states anyways.
This commit is contained in:
		
							parent
							
								
									31daaa7911
								
							
						
					
					
						commit
						ec0ce96c56
					
				@ -37,7 +37,7 @@ Stream::Stream(Core::Timing::CoreTiming& core_timing, u32 sample_rate, Format fo
 | 
				
			|||||||
    : 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 = core_timing.RegisterEvent(
 | 
					    release_event = Core::Timing::CreateEvent(
 | 
				
			||||||
        name, [this](u64 userdata, s64 cycles_late) { ReleaseActiveBuffer(); });
 | 
					        name, [this](u64 userdata, s64 cycles_late) { ReleaseActiveBuffer(); });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -103,7 +103,8 @@ private:
 | 
				
			|||||||
    float game_volume = 1.0f;         ///< The volume the game currently has set
 | 
					    float game_volume = 1.0f;         ///< The volume the game currently has set
 | 
				
			||||||
    ReleaseCallback release_callback; ///< Buffer release callback for the stream
 | 
					    ReleaseCallback release_callback; ///< Buffer release callback for the stream
 | 
				
			||||||
    State state{State::Stopped};      ///< Playback state of the stream
 | 
					    State state{State::Stopped};      ///< Playback state of the stream
 | 
				
			||||||
    Core::Timing::EventType* release_event{}; ///< Core timing release event for the stream
 | 
					    std::shared_ptr<Core::Timing::EventType>
 | 
				
			||||||
 | 
					        release_event;                      ///< Core timing release event for the stream
 | 
				
			||||||
    BufferPtr active_buffer;                ///< Actively playing buffer in the stream
 | 
					    BufferPtr active_buffer;                ///< Actively playing buffer in the stream
 | 
				
			||||||
    std::queue<BufferPtr> queued_buffers;   ///< Buffers queued to be played in the stream
 | 
					    std::queue<BufferPtr> queued_buffers;   ///< Buffers queued to be played in the stream
 | 
				
			||||||
    std::queue<BufferPtr> released_buffers; ///< Buffers recently released from the stream
 | 
					    std::queue<BufferPtr> released_buffers; ///< Buffers recently released from the stream
 | 
				
			||||||
 | 
				
			|||||||
@ -17,11 +17,15 @@ namespace Core::Timing {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
constexpr int MAX_SLICE_LENGTH = 10000;
 | 
					constexpr int MAX_SLICE_LENGTH = 10000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) {
 | 
				
			||||||
 | 
					    return std::make_shared<EventType>(std::move(callback), std::move(name));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct CoreTiming::Event {
 | 
					struct CoreTiming::Event {
 | 
				
			||||||
    s64 time;
 | 
					    s64 time;
 | 
				
			||||||
    u64 fifo_order;
 | 
					    u64 fifo_order;
 | 
				
			||||||
    u64 userdata;
 | 
					    u64 userdata;
 | 
				
			||||||
    const EventType* type;
 | 
					    std::weak_ptr<EventType> type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // 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
 | 
				
			||||||
@ -54,36 +58,15 @@ void CoreTiming::Initialize() {
 | 
				
			|||||||
    event_fifo_id = 0;
 | 
					    event_fifo_id = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const auto empty_timed_callback = [](u64, s64) {};
 | 
					    const auto empty_timed_callback = [](u64, s64) {};
 | 
				
			||||||
    ev_lost = RegisterEvent("_lost_event", empty_timed_callback);
 | 
					    ev_lost = CreateEvent("_lost_event", empty_timed_callback);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CoreTiming::Shutdown() {
 | 
					void CoreTiming::Shutdown() {
 | 
				
			||||||
    ClearPendingEvents();
 | 
					    ClearPendingEvents();
 | 
				
			||||||
    UnregisterAllEvents();
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
EventType* CoreTiming::RegisterEvent(const std::string& name, TimedCallback callback) {
 | 
					void CoreTiming::ScheduleEvent(s64 cycles_into_future, const std::shared_ptr<EventType>& event_type,
 | 
				
			||||||
    std::lock_guard guard{inner_mutex};
 | 
					                               u64 userdata) {
 | 
				
			||||||
    // check for existing type with same name.
 | 
					 | 
				
			||||||
    // we want event type names to remain unique so that we can use them for serialization.
 | 
					 | 
				
			||||||
    ASSERT_MSG(event_types.find(name) == event_types.end(),
 | 
					 | 
				
			||||||
               "CoreTiming Event \"{}\" is already registered. Events should only be registered "
 | 
					 | 
				
			||||||
               "during Init to avoid breaking save states.",
 | 
					 | 
				
			||||||
               name.c_str());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    auto info = event_types.emplace(name, EventType{callback, nullptr});
 | 
					 | 
				
			||||||
    EventType* event_type = &info.first->second;
 | 
					 | 
				
			||||||
    event_type->name = &info.first->first;
 | 
					 | 
				
			||||||
    return event_type;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void CoreTiming::UnregisterAllEvents() {
 | 
					 | 
				
			||||||
    ASSERT_MSG(event_queue.empty(), "Cannot unregister events with events pending");
 | 
					 | 
				
			||||||
    event_types.clear();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void CoreTiming::ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 userdata) {
 | 
					 | 
				
			||||||
    ASSERT(event_type != nullptr);
 | 
					 | 
				
			||||||
    std::lock_guard guard{inner_mutex};
 | 
					    std::lock_guard guard{inner_mutex};
 | 
				
			||||||
    const s64 timeout = GetTicks() + cycles_into_future;
 | 
					    const s64 timeout = GetTicks() + cycles_into_future;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -93,13 +76,15 @@ void CoreTiming::ScheduleEvent(s64 cycles_into_future, const EventType* event_ty
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    event_queue.emplace_back(Event{timeout, event_fifo_id++, userdata, event_type});
 | 
					    event_queue.emplace_back(Event{timeout, event_fifo_id++, userdata, event_type});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
 | 
					    std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CoreTiming::UnscheduleEvent(const EventType* event_type, u64 userdata) {
 | 
					void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type, u64 userdata) {
 | 
				
			||||||
    std::lock_guard guard{inner_mutex};
 | 
					    std::lock_guard guard{inner_mutex};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) {
 | 
					    const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) {
 | 
				
			||||||
        return e.type == event_type && e.userdata == userdata;
 | 
					        return e.type.lock().get() == event_type.get() && e.userdata == userdata;
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Removing random items breaks the invariant so we have to re-establish it.
 | 
					    // Removing random items breaks the invariant so we have to re-establish it.
 | 
				
			||||||
@ -130,10 +115,12 @@ void CoreTiming::ClearPendingEvents() {
 | 
				
			|||||||
    event_queue.clear();
 | 
					    event_queue.clear();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CoreTiming::RemoveEvent(const EventType* event_type) {
 | 
					void CoreTiming::RemoveEvent(const std::shared_ptr<EventType>& event_type) {
 | 
				
			||||||
    std::lock_guard guard{inner_mutex};
 | 
					    std::lock_guard guard{inner_mutex};
 | 
				
			||||||
    const auto itr = std::remove_if(event_queue.begin(), event_queue.end(),
 | 
					
 | 
				
			||||||
                                    [&](const Event& e) { return e.type == event_type; });
 | 
					    const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) {
 | 
				
			||||||
 | 
					        return e.type.lock().get() == event_type.get();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Removing random items breaks the invariant so we have to re-establish it.
 | 
					    // Removing random items breaks the invariant so we have to re-establish it.
 | 
				
			||||||
    if (itr != event_queue.end()) {
 | 
					    if (itr != event_queue.end()) {
 | 
				
			||||||
@ -181,7 +168,11 @@ void CoreTiming::Advance() {
 | 
				
			|||||||
        std::pop_heap(event_queue.begin(), event_queue.end(), std::greater<>());
 | 
					        std::pop_heap(event_queue.begin(), event_queue.end(), std::greater<>());
 | 
				
			||||||
        event_queue.pop_back();
 | 
					        event_queue.pop_back();
 | 
				
			||||||
        inner_mutex.unlock();
 | 
					        inner_mutex.unlock();
 | 
				
			||||||
        evt.type->callback(evt.userdata, global_timer - evt.time);
 | 
					
 | 
				
			||||||
 | 
					        if (auto event_type{evt.type.lock()}) {
 | 
				
			||||||
 | 
					            event_type->callback(evt.userdata, global_timer - evt.time);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        inner_mutex.lock();
 | 
					        inner_mutex.lock();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -6,11 +6,12 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <chrono>
 | 
					#include <chrono>
 | 
				
			||||||
#include <functional>
 | 
					#include <functional>
 | 
				
			||||||
 | 
					#include <memory>
 | 
				
			||||||
#include <mutex>
 | 
					#include <mutex>
 | 
				
			||||||
#include <optional>
 | 
					#include <optional>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
#include <unordered_map>
 | 
					 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "common/common_types.h"
 | 
					#include "common/common_types.h"
 | 
				
			||||||
#include "common/threadsafe_queue.h"
 | 
					#include "common/threadsafe_queue.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -21,10 +22,13 @@ using TimedCallback = std::function<void(u64 userdata, s64 cycles_late)>;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/// Contains the characteristics of a particular event.
 | 
					/// Contains the characteristics of a particular event.
 | 
				
			||||||
struct EventType {
 | 
					struct EventType {
 | 
				
			||||||
 | 
					    EventType(TimedCallback&& callback, std::string&& name)
 | 
				
			||||||
 | 
					        : callback{std::move(callback)}, name{std::move(name)} {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// The event's callback function.
 | 
					    /// The event's callback function.
 | 
				
			||||||
    TimedCallback callback;
 | 
					    TimedCallback callback;
 | 
				
			||||||
    /// A pointer to the name of the event.
 | 
					    /// A pointer to the name of the event.
 | 
				
			||||||
    const std::string* name;
 | 
					    const std::string name;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@ -57,31 +61,17 @@ public:
 | 
				
			|||||||
    /// Tears down all timing related functionality.
 | 
					    /// Tears down all timing related functionality.
 | 
				
			||||||
    void Shutdown();
 | 
					    void Shutdown();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Registers a core timing event with the given name and callback.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// @param name     The name of the core timing event to register.
 | 
					 | 
				
			||||||
    /// @param callback The callback to execute for the event.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// @returns An EventType instance representing the registered event.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// @pre The name of the event being registered must be unique among all
 | 
					 | 
				
			||||||
    ///      registered events.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    EventType* RegisterEvent(const std::string& name, TimedCallback callback);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Unregisters all registered events thus far. Note: not thread unsafe
 | 
					 | 
				
			||||||
    void UnregisterAllEvents();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// After the first Advance, the slice lengths and the downcount will be reduced whenever an
 | 
					    /// After the first Advance, the slice lengths and the downcount will be reduced whenever an
 | 
				
			||||||
    /// event is scheduled earlier than the current values.
 | 
					    /// event is scheduled earlier than the current values.
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// Scheduling from a callback will not update the downcount until the Advance() completes.
 | 
					    /// Scheduling from a callback will not update the downcount until the Advance() completes.
 | 
				
			||||||
    void ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 userdata = 0);
 | 
					    void ScheduleEvent(s64 cycles_into_future, const std::shared_ptr<EventType>& event_type,
 | 
				
			||||||
 | 
					                       u64 userdata = 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void UnscheduleEvent(const EventType* event_type, u64 userdata);
 | 
					    void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, u64 userdata);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// We only permit one event of each type in the queue at a time.
 | 
					    /// We only permit one event of each type in the queue at a time.
 | 
				
			||||||
    void RemoveEvent(const EventType* event_type);
 | 
					    void RemoveEvent(const std::shared_ptr<EventType>& event_type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void ForceExceptionCheck(s64 cycles);
 | 
					    void ForceExceptionCheck(s64 cycles);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -148,13 +138,18 @@ private:
 | 
				
			|||||||
    std::vector<Event> event_queue;
 | 
					    std::vector<Event> event_queue;
 | 
				
			||||||
    u64 event_fifo_id = 0;
 | 
					    u64 event_fifo_id = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Stores each element separately as a linked list node so pointers to elements
 | 
					    std::shared_ptr<EventType> ev_lost;
 | 
				
			||||||
    // remain stable regardless of rehashes/resizing.
 | 
					 | 
				
			||||||
    std::unordered_map<std::string, EventType> event_types;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    EventType* ev_lost = nullptr;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::mutex inner_mutex;
 | 
					    std::mutex inner_mutex;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Creates a core timing event with the given name and callback.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// @param name     The name of the core timing event to create.
 | 
				
			||||||
 | 
					/// @param callback The callback to execute for the event.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// @returns An EventType instance representing the created event.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace Core::Timing
 | 
					} // namespace Core::Timing
 | 
				
			||||||
 | 
				
			|||||||
@ -11,8 +11,7 @@
 | 
				
			|||||||
namespace Core::Hardware {
 | 
					namespace Core::Hardware {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
InterruptManager::InterruptManager(Core::System& system_in) : system(system_in) {
 | 
					InterruptManager::InterruptManager(Core::System& system_in) : system(system_in) {
 | 
				
			||||||
    gpu_interrupt_event =
 | 
					    gpu_interrupt_event = Core::Timing::CreateEvent("GPUInterrupt", [this](u64 message, s64) {
 | 
				
			||||||
        system.CoreTiming().RegisterEvent("GPUInterrupt", [this](u64 message, s64) {
 | 
					 | 
				
			||||||
        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);
 | 
				
			||||||
 | 
				
			|||||||
@ -4,6 +4,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <memory>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "common/common_types.h"
 | 
					#include "common/common_types.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Core {
 | 
					namespace Core {
 | 
				
			||||||
@ -25,7 +27,7 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
    Core::System& system;
 | 
					    Core::System& system;
 | 
				
			||||||
    Core::Timing::EventType* gpu_interrupt_event{};
 | 
					    std::shared_ptr<Core::Timing::EventType> gpu_interrupt_event;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace Core::Hardware
 | 
					} // namespace Core::Hardware
 | 
				
			||||||
 | 
				
			|||||||
@ -139,12 +139,12 @@ struct KernelCore::Impl {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    void InitializeThreads() {
 | 
					    void InitializeThreads() {
 | 
				
			||||||
        thread_wakeup_event_type =
 | 
					        thread_wakeup_event_type =
 | 
				
			||||||
            system.CoreTiming().RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback);
 | 
					            Core::Timing::CreateEvent("ThreadWakeupCallback", ThreadWakeupCallback);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void InitializePreemption() {
 | 
					    void InitializePreemption() {
 | 
				
			||||||
        preemption_event = system.CoreTiming().RegisterEvent(
 | 
					        preemption_event =
 | 
				
			||||||
            "PreemptionCallback", [this](u64 userdata, s64 cycles_late) {
 | 
					            Core::Timing::CreateEvent("PreemptionCallback", [this](u64 userdata, s64 cycles_late) {
 | 
				
			||||||
                global_scheduler.PreemptThreads();
 | 
					                global_scheduler.PreemptThreads();
 | 
				
			||||||
                s64 time_interval = Core::Timing::msToCycles(std::chrono::milliseconds(10));
 | 
					                s64 time_interval = Core::Timing::msToCycles(std::chrono::milliseconds(10));
 | 
				
			||||||
                system.CoreTiming().ScheduleEvent(time_interval, preemption_event);
 | 
					                system.CoreTiming().ScheduleEvent(time_interval, preemption_event);
 | 
				
			||||||
@ -166,8 +166,9 @@ struct KernelCore::Impl {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    std::shared_ptr<ResourceLimit> system_resource_limit;
 | 
					    std::shared_ptr<ResourceLimit> system_resource_limit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Core::Timing::EventType* thread_wakeup_event_type = nullptr;
 | 
					    std::shared_ptr<Core::Timing::EventType> thread_wakeup_event_type;
 | 
				
			||||||
    Core::Timing::EventType* preemption_event = nullptr;
 | 
					    std::shared_ptr<Core::Timing::EventType> preemption_event;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future,
 | 
					    // TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future,
 | 
				
			||||||
    // allowing us to simply use a pool index or similar.
 | 
					    // allowing us to simply use a pool index or similar.
 | 
				
			||||||
    Kernel::HandleTable thread_wakeup_callback_handle_table;
 | 
					    Kernel::HandleTable thread_wakeup_callback_handle_table;
 | 
				
			||||||
@ -269,7 +270,7 @@ u64 KernelCore::CreateNewUserProcessID() {
 | 
				
			|||||||
    return impl->next_user_process_id++;
 | 
					    return impl->next_user_process_id++;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Core::Timing::EventType* KernelCore::ThreadWakeupCallbackEventType() const {
 | 
					const std::shared_ptr<Core::Timing::EventType>& KernelCore::ThreadWakeupCallbackEventType() const {
 | 
				
			||||||
    return impl->thread_wakeup_event_type;
 | 
					    return impl->thread_wakeup_event_type;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -113,7 +113,7 @@ private:
 | 
				
			|||||||
    u64 CreateNewThreadID();
 | 
					    u64 CreateNewThreadID();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Retrieves the event type used for thread wakeup callbacks.
 | 
					    /// Retrieves the event type used for thread wakeup callbacks.
 | 
				
			||||||
    Core::Timing::EventType* ThreadWakeupCallbackEventType() const;
 | 
					    const std::shared_ptr<Core::Timing::EventType>& ThreadWakeupCallbackEventType() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Provides a reference to the thread wakeup callback handle table.
 | 
					    /// Provides a reference to the thread wakeup callback handle table.
 | 
				
			||||||
    Kernel::HandleTable& ThreadWakeupCallbackHandleTable();
 | 
					    Kernel::HandleTable& ThreadWakeupCallbackHandleTable();
 | 
				
			||||||
 | 
				
			|||||||
@ -77,15 +77,14 @@ IAppletResource::IAppletResource(Core::System& system)
 | 
				
			|||||||
    GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000);
 | 
					    GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Register update callbacks
 | 
					    // Register update callbacks
 | 
				
			||||||
    auto& core_timing = system.CoreTiming();
 | 
					 | 
				
			||||||
    pad_update_event =
 | 
					    pad_update_event =
 | 
				
			||||||
        core_timing.RegisterEvent("HID::UpdatePadCallback", [this](u64 userdata, s64 cycles_late) {
 | 
					        Core::Timing::CreateEvent("HID::UpdatePadCallback", [this](u64 userdata, s64 cycles_late) {
 | 
				
			||||||
            UpdateControllers(userdata, cycles_late);
 | 
					            UpdateControllers(userdata, cycles_late);
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?)
 | 
					    // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    core_timing.ScheduleEvent(pad_update_ticks, pad_update_event);
 | 
					    system.CoreTiming().ScheduleEvent(pad_update_ticks, pad_update_event);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ReloadInputDevices();
 | 
					    ReloadInputDevices();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -69,7 +69,7 @@ private:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    std::shared_ptr<Kernel::SharedMemory> shared_mem;
 | 
					    std::shared_ptr<Kernel::SharedMemory> shared_mem;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Core::Timing::EventType* pad_update_event;
 | 
					    std::shared_ptr<Core::Timing::EventType> pad_update_event;
 | 
				
			||||||
    Core::System& system;
 | 
					    Core::System& system;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)>
 | 
					    std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)>
 | 
				
			||||||
 | 
				
			|||||||
@ -37,8 +37,8 @@ NVFlinger::NVFlinger(Core::System& system) : system(system) {
 | 
				
			|||||||
    displays.emplace_back(4, "Null", system);
 | 
					    displays.emplace_back(4, "Null", system);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Schedule the screen composition events
 | 
					    // Schedule the screen composition events
 | 
				
			||||||
    composition_event = system.CoreTiming().RegisterEvent(
 | 
					    composition_event =
 | 
				
			||||||
        "ScreenComposition", [this](u64 userdata, s64 cycles_late) {
 | 
					        Core::Timing::CreateEvent("ScreenComposition", [this](u64 userdata, s64 cycles_late) {
 | 
				
			||||||
            Compose();
 | 
					            Compose();
 | 
				
			||||||
            const auto ticks =
 | 
					            const auto ticks =
 | 
				
			||||||
                Settings::values.force_30fps_mode ? frame_ticks_30fps : GetNextTicks();
 | 
					                Settings::values.force_30fps_mode ? frame_ticks_30fps : GetNextTicks();
 | 
				
			||||||
 | 
				
			|||||||
@ -103,7 +103,7 @@ private:
 | 
				
			|||||||
    u32 swap_interval = 1;
 | 
					    u32 swap_interval = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Event that handles screen composition.
 | 
					    /// Event that handles screen composition.
 | 
				
			||||||
    Core::Timing::EventType* composition_event;
 | 
					    std::shared_ptr<Core::Timing::EventType> composition_event;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Core::System& system;
 | 
					    Core::System& system;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -186,7 +186,7 @@ CheatEngine::~CheatEngine() {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CheatEngine::Initialize() {
 | 
					void CheatEngine::Initialize() {
 | 
				
			||||||
    event = core_timing.RegisterEvent(
 | 
					    event = Core::Timing::CreateEvent(
 | 
				
			||||||
        "CheatEngine::FrameCallback::" + Common::HexToString(metadata.main_nso_build_id),
 | 
					        "CheatEngine::FrameCallback::" + Common::HexToString(metadata.main_nso_build_id),
 | 
				
			||||||
        [this](u64 userdata, s64 cycles_late) { FrameCallback(userdata, cycles_late); });
 | 
					        [this](u64 userdata, s64 cycles_late) { FrameCallback(userdata, cycles_late); });
 | 
				
			||||||
    core_timing.ScheduleEvent(CHEAT_ENGINE_TICKS, event);
 | 
					    core_timing.ScheduleEvent(CHEAT_ENGINE_TICKS, event);
 | 
				
			||||||
 | 
				
			|||||||
@ -5,6 +5,7 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <atomic>
 | 
					#include <atomic>
 | 
				
			||||||
 | 
					#include <memory>
 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
#include "common/common_types.h"
 | 
					#include "common/common_types.h"
 | 
				
			||||||
#include "core/memory/dmnt_cheat_types.h"
 | 
					#include "core/memory/dmnt_cheat_types.h"
 | 
				
			||||||
@ -78,7 +79,7 @@ private:
 | 
				
			|||||||
    std::vector<CheatEntry> cheats;
 | 
					    std::vector<CheatEntry> cheats;
 | 
				
			||||||
    std::atomic_bool is_pending_reload{false};
 | 
					    std::atomic_bool is_pending_reload{false};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Core::Timing::EventType* event{};
 | 
					    std::shared_ptr<Core::Timing::EventType> event;
 | 
				
			||||||
    Core::Timing::CoreTiming& core_timing;
 | 
					    Core::Timing::CoreTiming& core_timing;
 | 
				
			||||||
    Core::System& system;
 | 
					    Core::System& system;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -54,7 +54,7 @@ void MemoryWriteWidth(u32 width, VAddr addr, u64 value) {
 | 
				
			|||||||
} // Anonymous namespace
 | 
					} // Anonymous namespace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Freezer::Freezer(Core::Timing::CoreTiming& core_timing) : core_timing(core_timing) {
 | 
					Freezer::Freezer(Core::Timing::CoreTiming& core_timing) : core_timing(core_timing) {
 | 
				
			||||||
    event = core_timing.RegisterEvent(
 | 
					    event = Core::Timing::CreateEvent(
 | 
				
			||||||
        "MemoryFreezer::FrameCallback",
 | 
					        "MemoryFreezer::FrameCallback",
 | 
				
			||||||
        [this](u64 userdata, s64 cycles_late) { FrameCallback(userdata, cycles_late); });
 | 
					        [this](u64 userdata, s64 cycles_late) { FrameCallback(userdata, cycles_late); });
 | 
				
			||||||
    core_timing.ScheduleEvent(MEMORY_FREEZER_TICKS, event);
 | 
					    core_timing.ScheduleEvent(MEMORY_FREEZER_TICKS, event);
 | 
				
			||||||
 | 
				
			|||||||
@ -5,6 +5,7 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <atomic>
 | 
					#include <atomic>
 | 
				
			||||||
 | 
					#include <memory>
 | 
				
			||||||
#include <mutex>
 | 
					#include <mutex>
 | 
				
			||||||
#include <optional>
 | 
					#include <optional>
 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
@ -75,7 +76,7 @@ private:
 | 
				
			|||||||
    mutable std::mutex entries_mutex;
 | 
					    mutable std::mutex entries_mutex;
 | 
				
			||||||
    std::vector<Entry> entries;
 | 
					    std::vector<Entry> entries;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Core::Timing::EventType* event;
 | 
					    std::shared_ptr<Core::Timing::EventType> event;
 | 
				
			||||||
    Core::Timing::CoreTiming& core_timing;
 | 
					    Core::Timing::CoreTiming& core_timing;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -7,7 +7,9 @@
 | 
				
			|||||||
#include <array>
 | 
					#include <array>
 | 
				
			||||||
#include <bitset>
 | 
					#include <bitset>
 | 
				
			||||||
#include <cstdlib>
 | 
					#include <cstdlib>
 | 
				
			||||||
 | 
					#include <memory>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "common/file_util.h"
 | 
					#include "common/file_util.h"
 | 
				
			||||||
#include "core/core.h"
 | 
					#include "core/core.h"
 | 
				
			||||||
#include "core/core_timing.h"
 | 
					#include "core/core_timing.h"
 | 
				
			||||||
@ -65,11 +67,16 @@ TEST_CASE("CoreTiming[BasicOrder]", "[core]") {
 | 
				
			|||||||
    ScopeInit guard;
 | 
					    ScopeInit guard;
 | 
				
			||||||
    auto& core_timing = guard.core_timing;
 | 
					    auto& core_timing = guard.core_timing;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Core::Timing::EventType* cb_a = core_timing.RegisterEvent("callbackA", CallbackTemplate<0>);
 | 
					    std::shared_ptr<Core::Timing::EventType> cb_a =
 | 
				
			||||||
    Core::Timing::EventType* cb_b = core_timing.RegisterEvent("callbackB", CallbackTemplate<1>);
 | 
					        Core::Timing::CreateEvent("callbackA", CallbackTemplate<0>);
 | 
				
			||||||
    Core::Timing::EventType* cb_c = core_timing.RegisterEvent("callbackC", CallbackTemplate<2>);
 | 
					    std::shared_ptr<Core::Timing::EventType> cb_b =
 | 
				
			||||||
    Core::Timing::EventType* cb_d = core_timing.RegisterEvent("callbackD", CallbackTemplate<3>);
 | 
					        Core::Timing::CreateEvent("callbackB", CallbackTemplate<1>);
 | 
				
			||||||
    Core::Timing::EventType* cb_e = core_timing.RegisterEvent("callbackE", CallbackTemplate<4>);
 | 
					    std::shared_ptr<Core::Timing::EventType> cb_c =
 | 
				
			||||||
 | 
					        Core::Timing::CreateEvent("callbackC", CallbackTemplate<2>);
 | 
				
			||||||
 | 
					    std::shared_ptr<Core::Timing::EventType> cb_d =
 | 
				
			||||||
 | 
					        Core::Timing::CreateEvent("callbackD", CallbackTemplate<3>);
 | 
				
			||||||
 | 
					    std::shared_ptr<Core::Timing::EventType> cb_e =
 | 
				
			||||||
 | 
					        Core::Timing::CreateEvent("callbackE", CallbackTemplate<4>);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Enter slice 0
 | 
					    // Enter slice 0
 | 
				
			||||||
    core_timing.ResetRun();
 | 
					    core_timing.ResetRun();
 | 
				
			||||||
@ -99,8 +106,8 @@ TEST_CASE("CoreTiming[FairSharing]", "[core]") {
 | 
				
			|||||||
    ScopeInit guard;
 | 
					    ScopeInit guard;
 | 
				
			||||||
    auto& core_timing = guard.core_timing;
 | 
					    auto& core_timing = guard.core_timing;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Core::Timing::EventType* empty_callback =
 | 
					    std::shared_ptr<Core::Timing::EventType> empty_callback =
 | 
				
			||||||
        core_timing.RegisterEvent("empty_callback", EmptyCallback);
 | 
					        Core::Timing::CreateEvent("empty_callback", EmptyCallback);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    callbacks_done = 0;
 | 
					    callbacks_done = 0;
 | 
				
			||||||
    u64 MAX_CALLBACKS = 10;
 | 
					    u64 MAX_CALLBACKS = 10;
 | 
				
			||||||
@ -133,8 +140,10 @@ TEST_CASE("Core::Timing[PredictableLateness]", "[core]") {
 | 
				
			|||||||
    ScopeInit guard;
 | 
					    ScopeInit guard;
 | 
				
			||||||
    auto& core_timing = guard.core_timing;
 | 
					    auto& core_timing = guard.core_timing;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Core::Timing::EventType* cb_a = core_timing.RegisterEvent("callbackA", CallbackTemplate<0>);
 | 
					    std::shared_ptr<Core::Timing::EventType> cb_a =
 | 
				
			||||||
    Core::Timing::EventType* cb_b = core_timing.RegisterEvent("callbackB", CallbackTemplate<1>);
 | 
					        Core::Timing::CreateEvent("callbackA", CallbackTemplate<0>);
 | 
				
			||||||
 | 
					    std::shared_ptr<Core::Timing::EventType> cb_b =
 | 
				
			||||||
 | 
					        Core::Timing::CreateEvent("callbackB", CallbackTemplate<1>);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Enter slice 0
 | 
					    // Enter slice 0
 | 
				
			||||||
    core_timing.ResetRun();
 | 
					    core_timing.ResetRun();
 | 
				
			||||||
@ -145,60 +154,3 @@ TEST_CASE("Core::Timing[PredictableLateness]", "[core]") {
 | 
				
			|||||||
    AdvanceAndCheck(core_timing, 0, 0, 10, -10); // (100 - 10)
 | 
					    AdvanceAndCheck(core_timing, 0, 0, 10, -10); // (100 - 10)
 | 
				
			||||||
    AdvanceAndCheck(core_timing, 1, 1, 50, -50);
 | 
					    AdvanceAndCheck(core_timing, 1, 1, 50, -50);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ChainSchedulingTest {
 | 
					 | 
				
			||||||
static int reschedules = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void RescheduleCallback(Core::Timing::CoreTiming& core_timing, u64 userdata,
 | 
					 | 
				
			||||||
                               s64 cycles_late) {
 | 
					 | 
				
			||||||
    --reschedules;
 | 
					 | 
				
			||||||
    REQUIRE(reschedules >= 0);
 | 
					 | 
				
			||||||
    REQUIRE(lateness == cycles_late);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (reschedules > 0) {
 | 
					 | 
				
			||||||
        core_timing.ScheduleEvent(1000, reinterpret_cast<Core::Timing::EventType*>(userdata),
 | 
					 | 
				
			||||||
                                  userdata);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
} // namespace ChainSchedulingTest
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_CASE("CoreTiming[ChainScheduling]", "[core]") {
 | 
					 | 
				
			||||||
    using namespace ChainSchedulingTest;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ScopeInit guard;
 | 
					 | 
				
			||||||
    auto& core_timing = guard.core_timing;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Core::Timing::EventType* cb_a = core_timing.RegisterEvent("callbackA", CallbackTemplate<0>);
 | 
					 | 
				
			||||||
    Core::Timing::EventType* cb_b = core_timing.RegisterEvent("callbackB", CallbackTemplate<1>);
 | 
					 | 
				
			||||||
    Core::Timing::EventType* cb_c = core_timing.RegisterEvent("callbackC", CallbackTemplate<2>);
 | 
					 | 
				
			||||||
    Core::Timing::EventType* cb_rs = core_timing.RegisterEvent(
 | 
					 | 
				
			||||||
        "callbackReschedule", [&core_timing](u64 userdata, s64 cycles_late) {
 | 
					 | 
				
			||||||
            RescheduleCallback(core_timing, userdata, cycles_late);
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Enter slice 0
 | 
					 | 
				
			||||||
    core_timing.ResetRun();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    core_timing.ScheduleEvent(800, cb_a, CB_IDS[0]);
 | 
					 | 
				
			||||||
    core_timing.ScheduleEvent(1000, cb_b, CB_IDS[1]);
 | 
					 | 
				
			||||||
    core_timing.ScheduleEvent(2200, cb_c, CB_IDS[2]);
 | 
					 | 
				
			||||||
    core_timing.ScheduleEvent(1000, cb_rs, reinterpret_cast<u64>(cb_rs));
 | 
					 | 
				
			||||||
    REQUIRE(800 == core_timing.GetDowncount());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    reschedules = 3;
 | 
					 | 
				
			||||||
    AdvanceAndCheck(core_timing, 0, 0); // cb_a
 | 
					 | 
				
			||||||
    AdvanceAndCheck(core_timing, 1, 1); // cb_b, cb_rs
 | 
					 | 
				
			||||||
    REQUIRE(2 == reschedules);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    core_timing.AddTicks(core_timing.GetDowncount());
 | 
					 | 
				
			||||||
    core_timing.Advance(); // cb_rs
 | 
					 | 
				
			||||||
    core_timing.SwitchContext(3);
 | 
					 | 
				
			||||||
    REQUIRE(1 == reschedules);
 | 
					 | 
				
			||||||
    REQUIRE(200 == core_timing.GetDowncount());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    AdvanceAndCheck(core_timing, 2, 3); // cb_c
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    core_timing.AddTicks(core_timing.GetDowncount());
 | 
					 | 
				
			||||||
    core_timing.Advance(); // cb_rs
 | 
					 | 
				
			||||||
    REQUIRE(0 == reschedules);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user