core/renderloop: add some hysteresis to triple buffering
Switching to triple buffering requires dropping a frame, so if we constantly switch back and forth between double and triple buffering, that can cause very visible performance issues CCBUG: 488843
This commit is contained in:
parent
6f750f0aa5
commit
0672313c20
2 changed files with 33 additions and 7 deletions
|
@ -62,17 +62,41 @@ void RenderLoopPrivate::scheduleRepaint(std::chrono::nanoseconds lastTargetTimes
|
|||
// -> take that into account and start compositing very early
|
||||
expectedCompositingTime = std::max(vblankInterval - 1us, expectedCompositingTime);
|
||||
}
|
||||
const uint64_t pageflipsInAdvance = std::min<int64_t>(expectedCompositingTime / vblankInterval + 1, maxPendingFrameCount);
|
||||
const uint64_t pageflipsSinceLastToTarget = std::max<int64_t>(std::round((lastTargetTimestamp - lastPresentationTimestamp).count() / double(vblankInterval.count())), 0);
|
||||
uint64_t pageflipsInAdvance = std::min<int64_t>(expectedCompositingTime / vblankInterval + 1, maxPendingFrameCount);
|
||||
|
||||
// switching from double to triple buffering causes a frame drop
|
||||
// -> apply some amount of hysteresis to avoid switching back and forth constantly
|
||||
if (pageflipsInAdvance > 1) {
|
||||
// immediately switch to triple buffering when needed
|
||||
wasTripleBuffering = true;
|
||||
doubleBufferingCounter = 0;
|
||||
} else if (wasTripleBuffering) {
|
||||
// but wait a bit before switching back to double buffering
|
||||
if (doubleBufferingCounter >= 10) {
|
||||
wasTripleBuffering = false;
|
||||
} else if (expectedCompositingTime >= vblankInterval * 0.95) {
|
||||
// also don't switch back if render times are just barely enough for double buffering
|
||||
pageflipsInAdvance = 2;
|
||||
doubleBufferingCounter = 0;
|
||||
} else {
|
||||
doubleBufferingCounter++;
|
||||
pageflipsInAdvance = 2;
|
||||
}
|
||||
}
|
||||
|
||||
nextPresentationTimestamp = lastPresentationTimestamp + std::max(pageflipsSince + pageflipsInAdvance, pageflipsSinceLastToTarget + 1) * vblankInterval;
|
||||
} else if (presentationMode == PresentationMode::Async || presentationMode == PresentationMode::AdaptiveAsync) {
|
||||
// tearing: pageflips happen ASAP
|
||||
nextPresentationTimestamp = currentTime;
|
||||
} else {
|
||||
// adaptive sync: pageflips happen after one vblank interval
|
||||
// TODO read minimum refresh rate from the EDID and take it into account here
|
||||
nextPresentationTimestamp = lastPresentationTimestamp + vblankInterval;
|
||||
wasTripleBuffering = false;
|
||||
doubleBufferingCounter = 0;
|
||||
if (presentationMode == PresentationMode::Async || presentationMode == PresentationMode::AdaptiveAsync) {
|
||||
// tearing: pageflips happen ASAP
|
||||
nextPresentationTimestamp = currentTime;
|
||||
} else {
|
||||
// adaptive sync: pageflips happen after one vblank interval
|
||||
// TODO read minimum refresh rate from the EDID and take it into account here
|
||||
nextPresentationTimestamp = lastPresentationTimestamp + vblankInterval;
|
||||
}
|
||||
}
|
||||
|
||||
const std::chrono::nanoseconds nextRenderTimestamp = nextPresentationTimestamp - expectedCompositingTime;
|
||||
|
|
|
@ -43,6 +43,8 @@ public:
|
|||
std::optional<std::fstream> m_debugOutput;
|
||||
std::chrono::nanoseconds lastPresentationTimestamp = std::chrono::nanoseconds::zero();
|
||||
std::chrono::nanoseconds nextPresentationTimestamp = std::chrono::nanoseconds::zero();
|
||||
bool wasTripleBuffering = false;
|
||||
int doubleBufferingCounter = 0;
|
||||
QTimer compositeTimer;
|
||||
RenderJournal renderJournal;
|
||||
int refreshRate = 60000;
|
||||
|
|
Loading…
Reference in a new issue