SF: Update vsync timeline validUntil to be exact vsync time.
Introduce Timeline::isWithin function that puts sourced vsync time
source into Unique, Shared and Outside categories.
BUG: 343603085
Test: atest VSyncPredictorTest
Flag: com.android.graphics.surfaceflinger.flags.vrr_bugfix_24q4
Change-Id: I99094e64c8403455158a6e794bd4d2ce32429f93
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index dd3c4b0..0644aca 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -360,7 +360,11 @@
purgeTimelines(now);
for (auto& timeline : mTimelines) {
- if (timeline.validUntil() && timeline.validUntil()->ns() > vsync) {
+ const bool isVsyncValid = FlagManager::getInstance().vrr_bugfix_24q4()
+ ? timeline.isWithin(TimePoint::fromNs(vsync)) ==
+ VsyncTimeline::VsyncOnTimeline::Unique
+ : timeline.validUntil() && timeline.validUntil()->ns() > vsync;
+ if (isVsyncValid) {
return timeline.isVSyncInPhase(model, vsync, frameRate);
}
}
@@ -395,8 +399,14 @@
mLastCommittedVsync = TimePoint::fromNs(0);
} else {
- mTimelines.back().freeze(
- TimePoint::fromNs(mLastCommittedVsync.ns() + mIdealPeriod.ns() / 2));
+ if (FlagManager::getInstance().vrr_bugfix_24q4()) {
+ // We need to freeze the timeline at the committed vsync so that we don't
+ // overshoot the deadline.
+ mTimelines.back().freeze(mLastCommittedVsync);
+ } else {
+ mTimelines.back().freeze(
+ TimePoint::fromNs(mLastCommittedVsync.ns() + mIdealPeriod.ns() / 2));
+ }
}
mTimelines.emplace_back(mLastCommittedVsync, mIdealPeriod, renderRate);
purgeTimelines(TimePoint::fromNs(mClock->now()));
@@ -611,7 +621,10 @@
while (mTimelines.size() > 1) {
const auto validUntilOpt = mTimelines.front().validUntil();
- if (validUntilOpt && *validUntilOpt < now) {
+ const bool isTimelineOutDated = FlagManager::getInstance().vrr_bugfix_24q4()
+ ? mTimelines.front().isWithin(now) == VsyncTimeline::VsyncOnTimeline::Outside
+ : validUntilOpt && *validUntilOpt < now;
+ if (isTimelineOutDated) {
mTimelines.pop_front();
} else {
break;
@@ -660,9 +673,12 @@
vsyncTime += missedVsync.fixup.ns();
ATRACE_FORMAT_INSTANT("lastFrameMissed");
} else if (mightBackpressure && lastVsyncOpt) {
- // lastVsyncOpt is based on the old timeline before we shifted it. we should correct it
- // first before trying to use it.
- lastVsyncOpt = snapToVsyncAlignedWithRenderRate(model, *lastVsyncOpt);
+ if (!FlagManager::getInstance().vrr_bugfix_24q4()) {
+ // lastVsyncOpt does not need to be corrected with the new rate, and
+ // it should be used as is to avoid skipping a frame when changing rates are
+ // aligned at vsync time.
+ lastVsyncOpt = snapToVsyncAlignedWithRenderRate(model, *lastVsyncOpt);
+ }
const auto vsyncDiff = vsyncTime - *lastVsyncOpt;
if (vsyncDiff <= minFramePeriodOpt->ns() - threshold) {
// avoid a duplicate vsync
@@ -681,7 +697,10 @@
}
ATRACE_FORMAT_INSTANT("vsync in %.2fms", float(vsyncTime - TimePoint::now().ns()) / 1e6f);
- if (mValidUntil && vsyncTime > mValidUntil->ns()) {
+ const bool isVsyncInvalid = FlagManager::getInstance().vrr_bugfix_24q4()
+ ? isWithin(TimePoint::fromNs(vsyncTime)) == VsyncOnTimeline::Outside
+ : mValidUntil && vsyncTime > mValidUntil->ns();
+ if (isVsyncInvalid) {
ATRACE_FORMAT_INSTANT("no longer valid for vsync in %.2f",
static_cast<float>(vsyncTime - TimePoint::now().ns()) / 1e6f);
return std::nullopt;