mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-02-20 19:54:19 +01:00
[util,dxvk] Limit frame rate based on deadline
This should work better now that present_wait is universally supported.
This commit is contained in:
parent
1811f4b995
commit
51f2e246fa
@ -667,10 +667,6 @@ namespace dxvk {
|
||||
if (!frame.frameId)
|
||||
return;
|
||||
|
||||
// Apply the FPS limiter before signaling the frame event in
|
||||
// order to reduce latency if the app uses it for frame pacing.
|
||||
m_fpsLimiter.delay();
|
||||
|
||||
// If the present operation has succeeded, actually wait for it to complete.
|
||||
// Don't bother with it on MAILBOX / IMMEDIATE modes since doing so would
|
||||
// restrict us to the display refresh rate on some platforms (XWayland).
|
||||
@ -685,6 +681,9 @@ namespace dxvk {
|
||||
// Always signal even on error, since failures here
|
||||
// are transparent to the front-end.
|
||||
m_signal->signal(frame.frameId);
|
||||
|
||||
// Apply FPS limtier here to align it as closely with scanout as we can.
|
||||
m_fpsLimiter.delay();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,9 +44,6 @@ namespace dxvk {
|
||||
|
||||
m_heuristicFrameCount = 0;
|
||||
m_heuristicEnable = false;
|
||||
|
||||
if (m_targetInterval != TimerDuration::zero() && !m_initialized)
|
||||
initialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -56,10 +53,11 @@ namespace dxvk {
|
||||
std::unique_lock<dxvk::mutex> lock(m_mutex);
|
||||
auto interval = m_targetInterval;
|
||||
|
||||
if (interval == TimerDuration::zero())
|
||||
if (interval == TimerDuration::zero()) {
|
||||
m_nextFrame = TimePoint();
|
||||
return;
|
||||
}
|
||||
|
||||
auto t0 = m_lastFrame;
|
||||
auto t1 = dxvk::high_resolution_clock::now();
|
||||
|
||||
if (interval < TimerDuration::zero()) {
|
||||
@ -73,27 +71,12 @@ namespace dxvk {
|
||||
// that can be written by setTargetFrameRate
|
||||
lock.unlock();
|
||||
|
||||
auto frameTime = std::chrono::duration_cast<TimerDuration>(t1 - t0);
|
||||
if (t1 < m_nextFrame)
|
||||
Sleep::sleepUntil(t1, m_nextFrame);
|
||||
|
||||
if (frameTime * 100 > interval * 103 - m_deviation * 100) {
|
||||
// If we have a slow frame, reset the deviation since we
|
||||
// do not want to compensate for low performance later on
|
||||
m_deviation = TimerDuration::zero();
|
||||
} else {
|
||||
// Don't call sleep if the amount of time to sleep is shorter
|
||||
// than the time the function calls are likely going to take
|
||||
TimerDuration sleepDuration = interval - m_deviation - frameTime;
|
||||
t1 = Sleep::sleepFor(t1, sleepDuration);
|
||||
|
||||
// Compensate for any sleep inaccuracies in the next frame, and
|
||||
// limit cumulative deviation in order to avoid stutter in case we
|
||||
// have a number of slow frames immediately followed by a fast one.
|
||||
frameTime = std::chrono::duration_cast<TimerDuration>(t1 - t0);
|
||||
m_deviation += frameTime - interval;
|
||||
m_deviation = std::min(m_deviation, interval / 16);
|
||||
}
|
||||
|
||||
m_lastFrame = t1;
|
||||
m_nextFrame = (t1 < m_nextFrame + interval)
|
||||
? m_nextFrame + interval
|
||||
: t1 + interval;
|
||||
}
|
||||
|
||||
|
||||
@ -131,10 +114,4 @@ namespace dxvk {
|
||||
return m_heuristicEnable;
|
||||
}
|
||||
|
||||
|
||||
void FpsLimiter::initialize() {
|
||||
m_lastFrame = dxvk::high_resolution_clock::now();
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -47,10 +47,8 @@ namespace dxvk {
|
||||
dxvk::mutex m_mutex;
|
||||
|
||||
TimerDuration m_targetInterval = TimerDuration::zero();
|
||||
TimerDuration m_deviation = TimerDuration::zero();
|
||||
TimePoint m_lastFrame = TimePoint();
|
||||
TimePoint m_nextFrame = TimePoint();
|
||||
|
||||
bool m_initialized = false;
|
||||
bool m_envOverride = false;
|
||||
|
||||
uint32_t m_heuristicFrameCount = 0;
|
||||
@ -59,8 +57,6 @@ namespace dxvk {
|
||||
|
||||
bool testRefreshHeuristic(TimerDuration interval, TimePoint now);
|
||||
|
||||
void initialize();
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user