mirror of
https://github.com/WinampDesktop/winamp.git
synced 2025-04-28 15:15:43 -04:00
System: Handle large event timing overshoots better
Usually a result of DMA cycle stealing. Instead of adding all time, add min(all_events.downcount) at a time. 1.5% performance improvement, but fixes desyncs between the SPU and CD-ROM.
This commit is contained in:
parent
0317541477
commit
dd48a1f585
@ -1090,52 +1090,56 @@ void System::RunEvents()
|
|||||||
{
|
{
|
||||||
DebugAssert(!m_running_events && !m_events.empty());
|
DebugAssert(!m_running_events && !m_events.empty());
|
||||||
|
|
||||||
const TickCount pending_ticks = m_cpu->GetPendingTicks();
|
|
||||||
m_global_tick_counter += static_cast<u32>(pending_ticks);
|
|
||||||
m_cpu->ResetPendingTicks();
|
|
||||||
|
|
||||||
TickCount time = static_cast<TickCount>(m_global_tick_counter - m_last_event_run_time);
|
|
||||||
m_running_events = true;
|
m_running_events = true;
|
||||||
|
|
||||||
|
TickCount pending_ticks = (m_global_tick_counter + m_cpu->GetPendingTicks()) - m_last_event_run_time;
|
||||||
|
m_cpu->ResetPendingTicks();
|
||||||
|
while (pending_ticks > 0)
|
||||||
|
{
|
||||||
|
const TickCount time = std::min(pending_ticks, m_events[0]->m_downcount);
|
||||||
|
m_global_tick_counter += static_cast<u32>(time);
|
||||||
|
pending_ticks -= time;
|
||||||
|
|
||||||
|
// Apply downcount to all events.
|
||||||
|
// This will result in a negative downcount for those events which are late.
|
||||||
|
for (TimingEvent* evt : m_events)
|
||||||
|
{
|
||||||
|
evt->m_downcount -= time;
|
||||||
|
evt->m_time_since_last_run += time;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we can actually run the callbacks.
|
||||||
|
while (m_events.front()->GetDowncount() <= 0)
|
||||||
|
{
|
||||||
|
TimingEvent* evt = m_events.front();
|
||||||
|
const TickCount ticks_late = -evt->m_downcount;
|
||||||
|
std::pop_heap(m_events.begin(), m_events.end(), CompareEvents);
|
||||||
|
|
||||||
|
// Factor late time into the time for the next invocation.
|
||||||
|
const TickCount ticks_to_execute = evt->m_time_since_last_run;
|
||||||
|
evt->m_downcount += evt->m_interval;
|
||||||
|
evt->m_time_since_last_run = 0;
|
||||||
|
|
||||||
|
// The cycles_late is only an indicator, it doesn't modify the cycles to execute.
|
||||||
|
evt->m_callback(ticks_to_execute, ticks_late);
|
||||||
|
|
||||||
|
// Place it in the appropriate position in the queue.
|
||||||
|
if (m_events_need_sorting)
|
||||||
|
{
|
||||||
|
// Another event may have been changed by this event, or the interval/downcount changed.
|
||||||
|
std::make_heap(m_events.begin(), m_events.end(), CompareEvents);
|
||||||
|
m_events_need_sorting = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Keep the event list in a heap. The event we just serviced will be in the last place,
|
||||||
|
// so we can use push_here instead of make_heap, which should be faster.
|
||||||
|
std::push_heap(m_events.begin(), m_events.end(), CompareEvents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m_last_event_run_time = m_global_tick_counter;
|
m_last_event_run_time = m_global_tick_counter;
|
||||||
|
|
||||||
// Apply downcount to all events.
|
|
||||||
// This will result in a negative downcount for those events which are late.
|
|
||||||
for (TimingEvent* evt : m_events)
|
|
||||||
{
|
|
||||||
evt->m_downcount -= time;
|
|
||||||
evt->m_time_since_last_run += time;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now we can actually run the callbacks.
|
|
||||||
while (m_events.front()->GetDowncount() <= 0)
|
|
||||||
{
|
|
||||||
TimingEvent* evt = m_events.front();
|
|
||||||
const TickCount ticks_late = -evt->m_downcount;
|
|
||||||
std::pop_heap(m_events.begin(), m_events.end(), CompareEvents);
|
|
||||||
|
|
||||||
// Factor late time into the time for the next invocation.
|
|
||||||
const TickCount ticks_to_execute = evt->m_time_since_last_run;
|
|
||||||
evt->m_downcount += evt->m_interval;
|
|
||||||
evt->m_time_since_last_run = 0;
|
|
||||||
|
|
||||||
// The cycles_late is only an indicator, it doesn't modify the cycles to execute.
|
|
||||||
evt->m_callback(ticks_to_execute, ticks_late);
|
|
||||||
|
|
||||||
// Place it in the appropriate position in the queue.
|
|
||||||
if (m_events_need_sorting)
|
|
||||||
{
|
|
||||||
// Another event may have been changed by this event, or the interval/downcount changed.
|
|
||||||
std::make_heap(m_events.begin(), m_events.end(), CompareEvents);
|
|
||||||
m_events_need_sorting = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Keep the event list in a heap. The event we just serviced will be in the last place,
|
|
||||||
// so we can use push_here instead of make_heap, which should be faster.
|
|
||||||
std::push_heap(m_events.begin(), m_events.end(), CompareEvents);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_running_events = false;
|
m_running_events = false;
|
||||||
m_cpu->SetDowncount(m_events.front()->GetDowncount());
|
m_cpu->SetDowncount(m_events.front()->GetDowncount());
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user