Revert "SF: Introduce VsyncTimeline to VsyncPredictor"
This reverts commit b6c7f880460c81a6ce49ccb3334e2d2e1e020f81.
Reason for revert: Regressions tracked as childs on b/326599221
Change-Id: Ic0f959113a2d434d3b6412c90b58b85e5151e436
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index 2f9dfea..8697696 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -45,35 +45,11 @@
static auto constexpr kMaxPercent = 100u;
-namespace {
-nsecs_t getVsyncFixup(VSyncPredictor::Model model, Period minFramePeriod, nsecs_t vsyncTime,
- std::optional<nsecs_t> lastVsyncOpt) {
- const auto threshold = model.slope / 2;
-
- if (FlagManager::getInstance().vrr_config() && lastVsyncOpt) {
- const auto vsyncDiff = vsyncTime - *lastVsyncOpt;
- if (vsyncDiff >= threshold && vsyncDiff <= minFramePeriod.ns() - threshold) {
- const auto vsyncFixup = *lastVsyncOpt + minFramePeriod.ns() - vsyncTime;
- ATRACE_FORMAT_INSTANT("minFramePeriod violation. next in %.2f which is %.2f from prev. "
- "adjust by %.2f",
- static_cast<float>(vsyncTime - TimePoint::now().ns()) / 1e6f,
- static_cast<float>(vsyncTime - *lastVsyncOpt) / 1e6f,
- static_cast<float>(vsyncFixup) / 1e6f);
- return vsyncFixup;
- }
- }
-
- return 0;
-}
-} // namespace
-
VSyncPredictor::~VSyncPredictor() = default;
-VSyncPredictor::VSyncPredictor(std::unique_ptr<Clock> clock, ftl::NonNull<DisplayModePtr> modePtr,
- size_t historySize, size_t minimumSamplesForPrediction,
- uint32_t outlierTolerancePercent)
- : mClock(std::move(clock)),
- mId(modePtr->getPhysicalDisplayId()),
+VSyncPredictor::VSyncPredictor(ftl::NonNull<DisplayModePtr> modePtr, size_t historySize,
+ size_t minimumSamplesForPrediction, uint32_t outlierTolerancePercent)
+ : mId(modePtr->getPhysicalDisplayId()),
mTraceOn(property_get_bool("debug.sf.vsp_trace", false)),
kHistorySize(historySize),
kMinimumSamplesForPrediction(minimumSamplesForPrediction),
@@ -171,7 +147,7 @@
mKnownTimestamp = timestamp;
}
ATRACE_FORMAT_INSTANT("timestamp rejected. mKnownTimestamp was %.2fms ago",
- (mClock->now() - *mKnownTimestamp) / 1e6f);
+ (systemTime() - *mKnownTimestamp) / 1e6f);
return false;
}
@@ -274,6 +250,17 @@
return true;
}
+auto VSyncPredictor::getVsyncSequenceLocked(nsecs_t timestamp) const -> VsyncSequence {
+ const auto vsync = snapToVsync(timestamp);
+ if (!mLastVsyncSequence) return {vsync, 0};
+
+ const auto [slope, _] = getVSyncPredictionModelLocked();
+ const auto [lastVsyncTime, lastVsyncSequence] = *mLastVsyncSequence;
+ const auto vsyncSequence = lastVsyncSequence +
+ static_cast<int64_t>(std::round((vsync - lastVsyncTime) / static_cast<float>(slope)));
+ return {vsync, vsyncSequence};
+}
+
nsecs_t VSyncPredictor::snapToVsync(nsecs_t timePoint) const {
auto const [slope, intercept] = getVSyncPredictionModelLocked();
@@ -311,32 +298,51 @@
}
nsecs_t VSyncPredictor::nextAnticipatedVSyncTimeFrom(nsecs_t timePoint,
- std::optional<nsecs_t> lastVsyncOpt) {
+ std::optional<nsecs_t> lastVsyncOpt) const {
ATRACE_CALL();
std::lock_guard lock(mMutex);
+ const auto currentPeriod = mRateMap.find(idealPeriod())->second.slope;
+ const auto threshold = currentPeriod / 2;
+ const auto minFramePeriod = minFramePeriodLocked().ns();
+ const auto lastFrameMissed =
+ lastVsyncOpt && std::abs(*lastVsyncOpt - mLastMissedVsync.ns()) < threshold;
+ const nsecs_t baseTime =
+ FlagManager::getInstance().vrr_config() && !lastFrameMissed && lastVsyncOpt
+ ? std::max(timePoint, *lastVsyncOpt + minFramePeriod - threshold)
+ : timePoint;
+ return snapToVsyncAlignedWithRenderRate(baseTime);
+}
- const auto now = TimePoint::fromNs(mClock->now());
- purgeTimelines(now);
+nsecs_t VSyncPredictor::snapToVsyncAlignedWithRenderRate(nsecs_t timePoint) const {
+ // update the mLastVsyncSequence for reference point
+ mLastVsyncSequence = getVsyncSequenceLocked(timePoint);
- std::optional<TimePoint> vsyncOpt;
- for (auto& timeline : mTimelines) {
- vsyncOpt = timeline.nextAnticipatedVSyncTimeFrom(getVSyncPredictionModelLocked(),
- minFramePeriodLocked(),
- snapToVsync(timePoint), mMissedVsync,
- lastVsyncOpt);
- if (vsyncOpt) {
- break;
+ const auto renderRatePhase = [&]() REQUIRES(mMutex) -> int {
+ if (!mRenderRateOpt) return 0;
+ const auto divisor =
+ RefreshRateSelector::getFrameRateDivisor(Fps::fromPeriodNsecs(idealPeriod()),
+ *mRenderRateOpt);
+ if (divisor <= 1) return 0;
+
+ int mod = mLastVsyncSequence->seq % divisor;
+ if (mod == 0) return 0;
+
+ // This is actually a bug fix, but guarded with vrr_config since we found it with this
+ // config
+ if (FlagManager::getInstance().vrr_config()) {
+ if (mod < 0) mod += divisor;
}
- }
- LOG_ALWAYS_FATAL_IF(!vsyncOpt);
- if (*vsyncOpt > mLastCommittedVsync) {
- mLastCommittedVsync = *vsyncOpt;
- ATRACE_FORMAT_INSTANT("mLastCommittedVsync in %.2fms",
- float(mLastCommittedVsync.ns() - mClock->now()) / 1e6f);
+ return divisor - mod;
+ }();
+
+ if (renderRatePhase == 0) {
+ return mLastVsyncSequence->vsyncTime;
}
- return vsyncOpt->ns();
+ auto const [slope, intercept] = getVSyncPredictionModelLocked();
+ const auto approximateNextVsync = mLastVsyncSequence->vsyncTime + slope * renderRatePhase;
+ return snapToVsync(approximateNextVsync - slope / 2);
}
/*
@@ -347,28 +353,32 @@
* isVSyncInPhase(33.3, 30) = false
* isVSyncInPhase(50.0, 30) = true
*/
-bool VSyncPredictor::isVSyncInPhase(nsecs_t timePoint, Fps frameRate) {
- if (timePoint == 0) {
+bool VSyncPredictor::isVSyncInPhase(nsecs_t timePoint, Fps frameRate) const {
+ std::lock_guard lock(mMutex);
+ const auto divisor =
+ RefreshRateSelector::getFrameRateDivisor(Fps::fromPeriodNsecs(idealPeriod()),
+ frameRate);
+ return isVSyncInPhaseLocked(timePoint, static_cast<unsigned>(divisor));
+}
+
+bool VSyncPredictor::isVSyncInPhaseLocked(nsecs_t timePoint, unsigned divisor) const {
+ const TimePoint now = TimePoint::now();
+ const auto getTimePointIn = [](TimePoint now, nsecs_t timePoint) -> float {
+ return ticks<std::milli, float>(TimePoint::fromNs(timePoint) - now);
+ };
+ ATRACE_FORMAT("%s timePoint in: %.2f divisor: %zu", __func__, getTimePointIn(now, timePoint),
+ divisor);
+
+ if (divisor <= 1 || timePoint == 0) {
return true;
}
- std::lock_guard lock(mMutex);
- const auto model = getVSyncPredictionModelLocked();
- const nsecs_t period = model.slope;
+ const nsecs_t period = mRateMap[idealPeriod()].slope;
const nsecs_t justBeforeTimePoint = timePoint - period / 2;
- const auto now = TimePoint::fromNs(mClock->now());
- const auto vsync = snapToVsync(justBeforeTimePoint);
-
- purgeTimelines(now);
-
- for (auto& timeline : mTimelines) {
- if (timeline.validUntil() && timeline.validUntil()->ns() > vsync) {
- return timeline.isVSyncInPhase(model, vsync, frameRate);
- }
- }
-
- // The last timeline should always be valid
- return mTimelines.back().isVSyncInPhase(model, vsync, frameRate);
+ const auto vsyncSequence = getVsyncSequenceLocked(justBeforeTimePoint);
+ ATRACE_FORMAT_INSTANT("vsync in: %.2f sequence: %" PRId64,
+ getTimePointIn(now, vsyncSequence.vsyncTime), vsyncSequence.seq);
+ return vsyncSequence.seq % divisor == 0;
}
void VSyncPredictor::setRenderRate(Fps renderRate) {
@@ -376,9 +386,6 @@
ALOGV("%s %s: RenderRate %s ", __func__, to_string(mId).c_str(), to_string(renderRate).c_str());
std::lock_guard lock(mMutex);
mRenderRateOpt = renderRate;
- mTimelines.back().freeze(TimePoint::fromNs(mLastCommittedVsync.ns() + mIdealPeriod.ns() / 2));
- mTimelines.emplace_back(mIdealPeriod, renderRate);
- purgeTimelines(TimePoint::fromNs(mClock->now()));
}
void VSyncPredictor::setDisplayModePtr(ftl::NonNull<DisplayModePtr> modePtr) {
@@ -408,9 +415,8 @@
clearTimestamps();
}
-Duration VSyncPredictor::ensureMinFrameDurationIsKept(TimePoint expectedPresentTime,
- TimePoint lastConfirmedPresentTime) {
- ATRACE_CALL();
+void VSyncPredictor::ensureMinFrameDurationIsKept(TimePoint expectedPresentTime,
+ TimePoint lastConfirmedPresentTime) {
const auto currentPeriod = mRateMap.find(idealPeriod())->second.slope;
const auto threshold = currentPeriod / 2;
const auto minFramePeriod = minFramePeriodLocked().ns();
@@ -436,20 +442,17 @@
if (!mPastExpectedPresentTimes.empty()) {
const auto phase = Duration(mPastExpectedPresentTimes.back() - expectedPresentTime);
if (phase > 0ns) {
- for (auto& timeline : mTimelines) {
- timeline.shiftVsyncSequence(phase);
+ if (mLastVsyncSequence) {
+ mLastVsyncSequence->vsyncTime += phase.ns();
}
mPastExpectedPresentTimes.clear();
- return phase;
}
}
-
- return 0ns;
}
void VSyncPredictor::onFrameBegin(TimePoint expectedPresentTime,
TimePoint lastConfirmedPresentTime) {
- ATRACE_NAME("VSyncPredictor::onFrameBegin");
+ ATRACE_CALL();
std::lock_guard lock(mMutex);
if (!mDisplayModePtr->getVrrConfig()) return;
@@ -479,14 +482,11 @@
}
}
- const auto phase = ensureMinFrameDurationIsKept(expectedPresentTime, lastConfirmedPresentTime);
- if (phase > 0ns) {
- mMissedVsync = {expectedPresentTime, minFramePeriodLocked()};
- }
+ ensureMinFrameDurationIsKept(expectedPresentTime, lastConfirmedPresentTime);
}
void VSyncPredictor::onFrameMissed(TimePoint expectedPresentTime) {
- ATRACE_NAME("VSyncPredictor::onFrameMissed");
+ ATRACE_CALL();
std::lock_guard lock(mMutex);
if (!mDisplayModePtr->getVrrConfig()) return;
@@ -496,15 +496,14 @@
const auto lastConfirmedPresentTime =
TimePoint::fromNs(expectedPresentTime.ns() + currentPeriod);
- const auto phase = ensureMinFrameDurationIsKept(expectedPresentTime, lastConfirmedPresentTime);
- if (phase > 0ns) {
- mMissedVsync = {expectedPresentTime, Duration::fromNs(0)};
- }
+ ensureMinFrameDurationIsKept(expectedPresentTime, lastConfirmedPresentTime);
+ mLastMissedVsync = expectedPresentTime;
}
VSyncPredictor::Model VSyncPredictor::getVSyncPredictionModel() const {
std::lock_guard lock(mMutex);
- return VSyncPredictor::getVSyncPredictionModelLocked();
+ const auto model = VSyncPredictor::getVSyncPredictionModelLocked();
+ return {model.slope, model.intercept};
}
VSyncPredictor::Model VSyncPredictor::getVSyncPredictionModelLocked() const {
@@ -525,11 +524,6 @@
mTimestamps.clear();
mLastTimestampIndex = 0;
}
-
- mTimelines.clear();
- mLastCommittedVsync = TimePoint::fromNs(0);
- mIdealPeriod = Period::fromNs(idealPeriod());
- mTimelines.emplace_back(mIdealPeriod, mRenderRateOpt);
}
bool VSyncPredictor::needsMoreSamples() const {
@@ -553,130 +547,6 @@
period / 1e6f, periodInterceptTuple.slope / 1e6f,
periodInterceptTuple.intercept);
}
- StringAppendF(&result, "\tmTimelines.size()=%zu\n", mTimelines.size());
-}
-
-void VSyncPredictor::purgeTimelines(android::TimePoint now) {
- while (mTimelines.size() > 1) {
- const auto validUntilOpt = mTimelines.front().validUntil();
- if (validUntilOpt && *validUntilOpt < now) {
- mTimelines.pop_front();
- } else {
- break;
- }
- }
- LOG_ALWAYS_FATAL_IF(mTimelines.empty());
- LOG_ALWAYS_FATAL_IF(mTimelines.back().validUntil().has_value());
-}
-
-VSyncPredictor::VsyncTimeline::VsyncTimeline(Period idealPeriod, std::optional<Fps> renderRateOpt)
- : mIdealPeriod(idealPeriod), mRenderRateOpt(renderRateOpt) {}
-
-void VSyncPredictor::VsyncTimeline::freeze(TimePoint lastVsync) {
- LOG_ALWAYS_FATAL_IF(mValidUntil.has_value());
- ATRACE_FORMAT_INSTANT("renderRate %s valid for %.2f",
- mRenderRateOpt ? to_string(*mRenderRateOpt).c_str() : "NA",
- float(lastVsync.ns() - TimePoint::now().ns()) / 1e6f);
- mValidUntil = lastVsync;
-}
-
-std::optional<TimePoint> VSyncPredictor::VsyncTimeline::nextAnticipatedVSyncTimeFrom(
- Model model, Period minFramePeriod, nsecs_t vsync, MissedVsync missedVsync,
- std::optional<nsecs_t> lastVsyncOpt) {
- ATRACE_FORMAT("renderRate %s", mRenderRateOpt ? to_string(*mRenderRateOpt).c_str() : "NA");
-
- const auto threshold = model.slope / 2;
- const auto lastFrameMissed =
- lastVsyncOpt && std::abs(*lastVsyncOpt - missedVsync.vsync.ns()) < threshold;
- nsecs_t vsyncTime = snapToVsyncAlignedWithRenderRate(model, vsync);
- nsecs_t vsyncFixupTime = 0;
- if (FlagManager::getInstance().vrr_config() && lastFrameMissed) {
- vsyncTime += missedVsync.fixup.ns();
- ATRACE_FORMAT_INSTANT("lastFrameMissed");
- } else {
- vsyncFixupTime = getVsyncFixup(model, minFramePeriod, vsyncTime, lastVsyncOpt);
- vsyncTime += vsyncFixupTime;
- }
-
- ATRACE_FORMAT_INSTANT("vsync in %.2fms", float(vsyncTime - TimePoint::now().ns()) / 1e6f);
- if (mValidUntil && vsyncTime > mValidUntil->ns()) {
- ATRACE_FORMAT_INSTANT("no longer valid for vsync in %.2f",
- static_cast<float>(vsyncTime - TimePoint::now().ns()) / 1e6f);
- return std::nullopt;
- }
-
- if (vsyncFixupTime > 0) {
- shiftVsyncSequence(Duration::fromNs(vsyncFixupTime));
- }
-
- return TimePoint::fromNs(vsyncTime);
-}
-
-auto VSyncPredictor::VsyncTimeline::getVsyncSequenceLocked(Model model, nsecs_t vsync)
- -> VsyncSequence {
- if (!mLastVsyncSequence) return {vsync, 0};
-
- const auto [lastVsyncTime, lastVsyncSequence] = *mLastVsyncSequence;
- const auto vsyncSequence = lastVsyncSequence +
- static_cast<int64_t>(std::round((vsync - lastVsyncTime) /
- static_cast<float>(model.slope)));
- return {vsync, vsyncSequence};
-}
-
-nsecs_t VSyncPredictor::VsyncTimeline::snapToVsyncAlignedWithRenderRate(Model model,
- nsecs_t vsync) {
- // update the mLastVsyncSequence for reference point
- mLastVsyncSequence = getVsyncSequenceLocked(model, vsync);
-
- const auto renderRatePhase = [&]() -> int {
- if (!mRenderRateOpt) return 0;
- const auto divisor =
- RefreshRateSelector::getFrameRateDivisor(Fps::fromPeriodNsecs(mIdealPeriod.ns()),
- *mRenderRateOpt);
- if (divisor <= 1) return 0;
-
- int mod = mLastVsyncSequence->seq % divisor;
- if (mod == 0) return 0;
-
- // This is actually a bug fix, but guarded with vrr_config since we found it with this
- // config
- if (FlagManager::getInstance().vrr_config()) {
- if (mod < 0) mod += divisor;
- }
-
- return divisor - mod;
- }();
-
- if (renderRatePhase == 0) {
- return mLastVsyncSequence->vsyncTime;
- }
-
- return mLastVsyncSequence->vsyncTime + model.slope * renderRatePhase;
-}
-
-bool VSyncPredictor::VsyncTimeline::isVSyncInPhase(Model model, nsecs_t vsync, Fps frameRate) {
- const auto getVsyncIn = [](TimePoint now, nsecs_t timePoint) -> float {
- return ticks<std::milli, float>(TimePoint::fromNs(timePoint) - now);
- };
-
- Fps displayFps = mRenderRateOpt ? *mRenderRateOpt : Fps::fromPeriodNsecs(mIdealPeriod.ns());
- const auto divisor = RefreshRateSelector::getFrameRateDivisor(displayFps, frameRate);
- const auto now = TimePoint::now();
-
- if (divisor <= 1) {
- return true;
- }
- const auto vsyncSequence = getVsyncSequenceLocked(model, vsync);
- ATRACE_FORMAT_INSTANT("vsync in: %.2f sequence: %" PRId64 " divisor: %zu",
- getVsyncIn(now, vsyncSequence.vsyncTime), vsyncSequence.seq, divisor);
- return vsyncSequence.seq % divisor == 0;
-}
-
-void VSyncPredictor::VsyncTimeline::shiftVsyncSequence(Duration phase) {
- if (mLastVsyncSequence) {
- ATRACE_FORMAT_INSTANT("adjusting vsync by %.2f", static_cast<float>(phase.ns()) / 1e6f);
- mLastVsyncSequence->vsyncTime += phase.ns();
- }
}
} // namespace android::scheduler