CoreTiming: Add support for secondary event type that does not affect timing.

This commit is contained in:
Admiral H. Curtiss 2023-01-02 03:27:45 +01:00
commit 1ce5e2425d
No known key found for this signature in database
GPG key ID: F051B4C4044F33FB
2 changed files with 54 additions and 0 deletions

View file

@ -212,6 +212,9 @@ void CoreTimingManager::DoState(PointerWrap& p)
// The stave state has changed the time, so our previous Throttle targets are invalid.
// Especially when global_time goes down; So we create a fake throttle update.
ResetThrottle(m_globals.global_timer);
// Throw away pending external events when loading state, they no longer apply.
m_external_event_queue.clear();
}
}
@ -282,6 +285,24 @@ void CoreTimingManager::ScheduleEvent(s64 cycles_into_future, EventType* event_t
}
}
void CoreTimingManager::ScheduleExternalEvent(u64 timepoint, EventType* event_type, u64 userdata,
u64 unique_id)
{
if (Core::IsCPUThread())
{
m_external_event_queue.emplace_back(
Event{static_cast<s64>(timepoint), unique_id, userdata, event_type});
std::push_heap(m_external_event_queue.begin(), m_external_event_queue.end(),
std::greater<Event>());
}
else
{
std::lock_guard lk(m_ts_write_lock);
m_external_pending_queue.Push(
Event{static_cast<s64>(timepoint), unique_id, userdata, event_type});
}
}
void CoreTimingManager::RemoveEvent(EventType* event_type)
{
auto itr = std::remove_if(m_event_queue.begin(), m_event_queue.end(),
@ -322,6 +343,13 @@ void CoreTimingManager::MoveEvents()
m_event_queue.emplace_back(std::move(ev));
std::push_heap(m_event_queue.begin(), m_event_queue.end(), std::greater<Event>());
}
for (Event ev; m_external_pending_queue.Pop(ev);)
{
m_external_event_queue.emplace_back(std::move(ev));
std::push_heap(m_external_event_queue.begin(), m_external_event_queue.end(),
std::greater<Event>());
}
}
void CoreTimingManager::Advance()
@ -351,6 +379,16 @@ void CoreTimingManager::Advance()
evt.type->callback(m_system, evt.userdata, m_globals.global_timer - evt.time);
}
while (!m_external_event_queue.empty() &&
m_external_event_queue.front().time <= m_globals.global_timer)
{
Event evt = std::move(m_external_event_queue.front());
std::pop_heap(m_external_event_queue.begin(), m_external_event_queue.end(),
std::greater<Event>());
m_external_event_queue.pop_back();
evt.type->callback(m_system, evt.userdata, m_globals.global_timer - evt.time);
}
m_is_global_timer_sane = false;
// Still events left (scheduled in the future)

View file

@ -104,6 +104,13 @@ public:
void ScheduleEvent(s64 cycles_into_future, EventType* event_type, u64 userdata = 0,
FromThread from = FromThread::CPU);
// Similar to ScheduleEvent, but enqueues an event in the secondary event queue that does not
// affect timing logic and isn't savestated. Used primarily for handling events in a deterministic
// manner during netplay. Note that 'timepoint' is absolute (instead of ScheduleEvent's relative)
// and that the user should try to provide a 'unique_id' for consistent event ordering if they
// happen to be at the same timepoint.
void ScheduleExternalEvent(u64 timepoint, EventType* event_type, u64 userdata, u64 unique_id);
// We only permit one event of each type in the queue at a time.
void RemoveEvent(EventType* event_type);
void RemoveAllEvents(EventType* event_type);
@ -172,6 +179,15 @@ private:
std::mutex m_ts_write_lock;
Common::SPSCQueue<Event, false> m_ts_queue;
// A second event queue that is used for timing 'external' events that are sent by the emulator
// rather than by the emulated game. Netplay uses these for syncing non-controller-button events
// sent by a single client, such as a press of the physical Reset button on the console, or an
// unplugging of a controller. These don't affect timing logic (and thus will not run at a precise
// time, but instead at the first opportunity given by the regular events) and do not get written
// to savestates.
std::vector<Event> m_external_event_queue;
Common::SPSCQueue<Event, false> m_external_pending_queue;
float m_last_oc_factor = 0.0f;
s64 m_idled_cycles = 0;