Loading services/surfaceflinger/Scheduler/Scheduler.cpp +13 −0 Original line number Diff line number Diff line Loading @@ -223,6 +223,19 @@ void Scheduler::onFrameSignal(ICompositor& compositor, VsyncId vsyncId, mPacesetterFrameDurationFractionToSkip = 0.f; } if (FlagManager::getInstance().vrr_config()) { const auto minFramePeriod = pacesetterOpt->get().schedulePtr->minFramePeriod(); const auto presentFenceForPastVsync = pacesetterTargeter.target().presentFenceForPastVsync(minFramePeriod); const auto lastConfirmedPresentTime = presentFenceForPastVsync->getSignalTime(); if (lastConfirmedPresentTime != Fence::SIGNAL_TIME_PENDING && lastConfirmedPresentTime != Fence::SIGNAL_TIME_INVALID) { pacesetterOpt->get() .schedulePtr->getTracker() .onFrameBegin(expectedVsyncTime, TimePoint::fromNs(lastConfirmedPresentTime)); } } const auto resultsPerDisplay = compositor.composite(pacesetterId, targeters); compositor.sample(); Loading services/surfaceflinger/Scheduler/VSyncPredictor.cpp +100 −2 Original line number Diff line number Diff line Loading @@ -114,6 +114,10 @@ Period VSyncPredictor::minFramePeriod() const { } std::lock_guard lock(mMutex); return minFramePeriodLocked(); } Period VSyncPredictor::minFramePeriodLocked() const { const auto idealPeakRefreshPeriod = mDisplayModePtr->getPeakFps().getPeriodNsecs(); const auto numPeriods = static_cast<int>(std::round(static_cast<float>(idealPeakRefreshPeriod) / static_cast<float>(idealPeriod()))); Loading Loading @@ -297,15 +301,20 @@ nsecs_t VSyncPredictor::nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const { const auto renderRatePhase = [&]() REQUIRES(mMutex) -> int { if (!mRenderRateOpt) return 0; const auto divisor = RefreshRateSelector::getFrameRateDivisor(Fps::fromPeriodNsecs(idealPeriod()), *mRenderRateOpt); if (divisor <= 1) return 0; const int mod = mLastVsyncSequence->seq % divisor; 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; }(); Loading Loading @@ -406,6 +415,95 @@ void VSyncPredictor::setDisplayModePtr(ftl::NonNull<DisplayModePtr> modePtr) { clearTimestamps(); } 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(); auto prev = lastConfirmedPresentTime.ns(); for (auto& current : mPastExpectedPresentTimes) { if (CC_UNLIKELY(mTraceOn)) { ATRACE_FORMAT_INSTANT("current %.2f past last signaled fence", static_cast<float>(current.ns() - lastConfirmedPresentTime.ns()) / 1e6f); } const auto minPeriodViolation = current.ns() - prev + threshold < minFramePeriod; if (minPeriodViolation) { ATRACE_NAME("minPeriodViolation"); current = TimePoint::fromNs(prev + minFramePeriod); prev = current.ns(); } else { break; } } if (!mPastExpectedPresentTimes.empty()) { const auto phase = Duration(mPastExpectedPresentTimes.back() - expectedPresentTime); if (phase > 0ns) { if (mLastVsyncSequence) { mLastVsyncSequence->vsyncTime += phase.ns(); } } } } void VSyncPredictor::onFrameBegin(TimePoint expectedPresentTime, TimePoint lastConfirmedPresentTime) { ATRACE_CALL(); std::lock_guard lock(mMutex); if (!mDisplayModePtr->getVrrConfig()) return; if (CC_UNLIKELY(mTraceOn)) { ATRACE_FORMAT_INSTANT("vsync is %.2f past last signaled fence", static_cast<float>(expectedPresentTime.ns() - lastConfirmedPresentTime.ns()) / 1e6f); } mPastExpectedPresentTimes.push_back(expectedPresentTime); const auto currentPeriod = mRateMap.find(idealPeriod())->second.slope; const auto threshold = currentPeriod / 2; const auto minFramePeriod = minFramePeriodLocked().ns(); while (!mPastExpectedPresentTimes.empty()) { const auto front = mPastExpectedPresentTimes.front().ns(); const bool frontIsLastConfirmed = std::abs(front - lastConfirmedPresentTime.ns()) < threshold; const bool frontIsBeforeConfirmed = front < lastConfirmedPresentTime.ns() - minFramePeriod + threshold; if (frontIsLastConfirmed || frontIsBeforeConfirmed) { if (CC_UNLIKELY(mTraceOn)) { ATRACE_FORMAT_INSTANT("Discarding old vsync - %.2f before last signaled fence", static_cast<float>(lastConfirmedPresentTime.ns() - mPastExpectedPresentTimes.front().ns()) / 1e6f); } mPastExpectedPresentTimes.pop_front(); } else { break; } } ensureMinFrameDurationIsKept(expectedPresentTime, lastConfirmedPresentTime); } void VSyncPredictor::onFrameMissed(TimePoint expectedPresentTime) { ATRACE_CALL(); std::lock_guard lock(mMutex); if (!mDisplayModePtr->getVrrConfig()) return; // We don't know when the frame is going to be presented, so we assume it missed one vsync const auto currentPeriod = mRateMap.find(idealPeriod())->second.slope; const auto lastConfirmedPresentTime = TimePoint::fromNs(expectedPresentTime.ns() + currentPeriod); ensureMinFrameDurationIsKept(expectedPresentTime, lastConfirmedPresentTime); } VSyncPredictor::Model VSyncPredictor::getVSyncPredictionModel() const { std::lock_guard lock(mMutex); const auto model = VSyncPredictor::getVSyncPredictionModelLocked(); Loading services/surfaceflinger/Scheduler/VSyncPredictor.h +9 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #pragma once #include <deque> #include <mutex> #include <unordered_map> #include <vector> Loading Loading @@ -67,6 +68,10 @@ public: void setRenderRate(Fps) final EXCLUDES(mMutex); void onFrameBegin(TimePoint expectedPresentTime, TimePoint lastConfirmedPresentTime) final EXCLUDES(mMutex); void onFrameMissed(TimePoint expectedPresentTime) final EXCLUDES(mMutex); void dump(std::string& result) const final EXCLUDES(mMutex); private: Loading @@ -84,6 +89,8 @@ private: Model getVSyncPredictionModelLocked() const REQUIRES(mMutex); nsecs_t nextAnticipatedVSyncTimeFromLocked(nsecs_t timePoint) const REQUIRES(mMutex); bool isVSyncInPhaseLocked(nsecs_t timePoint, unsigned divisor) const REQUIRES(mMutex); Period minFramePeriodLocked() const REQUIRES(mMutex); void ensureMinFrameDurationIsKept(TimePoint, TimePoint) REQUIRES(mMutex); struct VsyncSequence { nsecs_t vsyncTime; Loading Loading @@ -111,6 +118,8 @@ private: std::optional<Fps> mRenderRateOpt GUARDED_BY(mMutex); mutable std::optional<VsyncSequence> mLastVsyncSequence GUARDED_BY(mMutex); std::deque<TimePoint> mPastExpectedPresentTimes GUARDED_BY(mMutex); }; } // namespace android::scheduler services/surfaceflinger/Scheduler/VSyncTracker.h +5 −0 Original line number Diff line number Diff line Loading @@ -107,6 +107,11 @@ public: */ virtual void setRenderRate(Fps) = 0; virtual void onFrameBegin(TimePoint expectedPresentTime, TimePoint lastConfirmedPresentTime) = 0; virtual void onFrameMissed(TimePoint expectedPresentTime) = 0; virtual void dump(std::string& result) const = 0; protected: Loading services/surfaceflinger/SurfaceFlinger.cpp +4 −0 Original line number Diff line number Diff line Loading @@ -2476,6 +2476,10 @@ bool SurfaceFlinger::commit(PhysicalDisplayId pacesetterId, if (pacesetterFrameTarget.isFramePending()) { if (mBackpressureGpuComposition || pacesetterFrameTarget.didMissHwcFrame()) { if (FlagManager::getInstance().vrr_config()) { mScheduler->getVsyncSchedule()->getTracker().onFrameMissed( pacesetterFrameTarget.expectedPresentTime()); } scheduleCommit(FrameHint::kNone); return false; } Loading Loading
services/surfaceflinger/Scheduler/Scheduler.cpp +13 −0 Original line number Diff line number Diff line Loading @@ -223,6 +223,19 @@ void Scheduler::onFrameSignal(ICompositor& compositor, VsyncId vsyncId, mPacesetterFrameDurationFractionToSkip = 0.f; } if (FlagManager::getInstance().vrr_config()) { const auto minFramePeriod = pacesetterOpt->get().schedulePtr->minFramePeriod(); const auto presentFenceForPastVsync = pacesetterTargeter.target().presentFenceForPastVsync(minFramePeriod); const auto lastConfirmedPresentTime = presentFenceForPastVsync->getSignalTime(); if (lastConfirmedPresentTime != Fence::SIGNAL_TIME_PENDING && lastConfirmedPresentTime != Fence::SIGNAL_TIME_INVALID) { pacesetterOpt->get() .schedulePtr->getTracker() .onFrameBegin(expectedVsyncTime, TimePoint::fromNs(lastConfirmedPresentTime)); } } const auto resultsPerDisplay = compositor.composite(pacesetterId, targeters); compositor.sample(); Loading
services/surfaceflinger/Scheduler/VSyncPredictor.cpp +100 −2 Original line number Diff line number Diff line Loading @@ -114,6 +114,10 @@ Period VSyncPredictor::minFramePeriod() const { } std::lock_guard lock(mMutex); return minFramePeriodLocked(); } Period VSyncPredictor::minFramePeriodLocked() const { const auto idealPeakRefreshPeriod = mDisplayModePtr->getPeakFps().getPeriodNsecs(); const auto numPeriods = static_cast<int>(std::round(static_cast<float>(idealPeakRefreshPeriod) / static_cast<float>(idealPeriod()))); Loading Loading @@ -297,15 +301,20 @@ nsecs_t VSyncPredictor::nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const { const auto renderRatePhase = [&]() REQUIRES(mMutex) -> int { if (!mRenderRateOpt) return 0; const auto divisor = RefreshRateSelector::getFrameRateDivisor(Fps::fromPeriodNsecs(idealPeriod()), *mRenderRateOpt); if (divisor <= 1) return 0; const int mod = mLastVsyncSequence->seq % divisor; 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; }(); Loading Loading @@ -406,6 +415,95 @@ void VSyncPredictor::setDisplayModePtr(ftl::NonNull<DisplayModePtr> modePtr) { clearTimestamps(); } 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(); auto prev = lastConfirmedPresentTime.ns(); for (auto& current : mPastExpectedPresentTimes) { if (CC_UNLIKELY(mTraceOn)) { ATRACE_FORMAT_INSTANT("current %.2f past last signaled fence", static_cast<float>(current.ns() - lastConfirmedPresentTime.ns()) / 1e6f); } const auto minPeriodViolation = current.ns() - prev + threshold < minFramePeriod; if (minPeriodViolation) { ATRACE_NAME("minPeriodViolation"); current = TimePoint::fromNs(prev + minFramePeriod); prev = current.ns(); } else { break; } } if (!mPastExpectedPresentTimes.empty()) { const auto phase = Duration(mPastExpectedPresentTimes.back() - expectedPresentTime); if (phase > 0ns) { if (mLastVsyncSequence) { mLastVsyncSequence->vsyncTime += phase.ns(); } } } } void VSyncPredictor::onFrameBegin(TimePoint expectedPresentTime, TimePoint lastConfirmedPresentTime) { ATRACE_CALL(); std::lock_guard lock(mMutex); if (!mDisplayModePtr->getVrrConfig()) return; if (CC_UNLIKELY(mTraceOn)) { ATRACE_FORMAT_INSTANT("vsync is %.2f past last signaled fence", static_cast<float>(expectedPresentTime.ns() - lastConfirmedPresentTime.ns()) / 1e6f); } mPastExpectedPresentTimes.push_back(expectedPresentTime); const auto currentPeriod = mRateMap.find(idealPeriod())->second.slope; const auto threshold = currentPeriod / 2; const auto minFramePeriod = minFramePeriodLocked().ns(); while (!mPastExpectedPresentTimes.empty()) { const auto front = mPastExpectedPresentTimes.front().ns(); const bool frontIsLastConfirmed = std::abs(front - lastConfirmedPresentTime.ns()) < threshold; const bool frontIsBeforeConfirmed = front < lastConfirmedPresentTime.ns() - minFramePeriod + threshold; if (frontIsLastConfirmed || frontIsBeforeConfirmed) { if (CC_UNLIKELY(mTraceOn)) { ATRACE_FORMAT_INSTANT("Discarding old vsync - %.2f before last signaled fence", static_cast<float>(lastConfirmedPresentTime.ns() - mPastExpectedPresentTimes.front().ns()) / 1e6f); } mPastExpectedPresentTimes.pop_front(); } else { break; } } ensureMinFrameDurationIsKept(expectedPresentTime, lastConfirmedPresentTime); } void VSyncPredictor::onFrameMissed(TimePoint expectedPresentTime) { ATRACE_CALL(); std::lock_guard lock(mMutex); if (!mDisplayModePtr->getVrrConfig()) return; // We don't know when the frame is going to be presented, so we assume it missed one vsync const auto currentPeriod = mRateMap.find(idealPeriod())->second.slope; const auto lastConfirmedPresentTime = TimePoint::fromNs(expectedPresentTime.ns() + currentPeriod); ensureMinFrameDurationIsKept(expectedPresentTime, lastConfirmedPresentTime); } VSyncPredictor::Model VSyncPredictor::getVSyncPredictionModel() const { std::lock_guard lock(mMutex); const auto model = VSyncPredictor::getVSyncPredictionModelLocked(); Loading
services/surfaceflinger/Scheduler/VSyncPredictor.h +9 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #pragma once #include <deque> #include <mutex> #include <unordered_map> #include <vector> Loading Loading @@ -67,6 +68,10 @@ public: void setRenderRate(Fps) final EXCLUDES(mMutex); void onFrameBegin(TimePoint expectedPresentTime, TimePoint lastConfirmedPresentTime) final EXCLUDES(mMutex); void onFrameMissed(TimePoint expectedPresentTime) final EXCLUDES(mMutex); void dump(std::string& result) const final EXCLUDES(mMutex); private: Loading @@ -84,6 +89,8 @@ private: Model getVSyncPredictionModelLocked() const REQUIRES(mMutex); nsecs_t nextAnticipatedVSyncTimeFromLocked(nsecs_t timePoint) const REQUIRES(mMutex); bool isVSyncInPhaseLocked(nsecs_t timePoint, unsigned divisor) const REQUIRES(mMutex); Period minFramePeriodLocked() const REQUIRES(mMutex); void ensureMinFrameDurationIsKept(TimePoint, TimePoint) REQUIRES(mMutex); struct VsyncSequence { nsecs_t vsyncTime; Loading Loading @@ -111,6 +118,8 @@ private: std::optional<Fps> mRenderRateOpt GUARDED_BY(mMutex); mutable std::optional<VsyncSequence> mLastVsyncSequence GUARDED_BY(mMutex); std::deque<TimePoint> mPastExpectedPresentTimes GUARDED_BY(mMutex); }; } // namespace android::scheduler
services/surfaceflinger/Scheduler/VSyncTracker.h +5 −0 Original line number Diff line number Diff line Loading @@ -107,6 +107,11 @@ public: */ virtual void setRenderRate(Fps) = 0; virtual void onFrameBegin(TimePoint expectedPresentTime, TimePoint lastConfirmedPresentTime) = 0; virtual void onFrameMissed(TimePoint expectedPresentTime) = 0; virtual void dump(std::string& result) const = 0; protected: Loading
services/surfaceflinger/SurfaceFlinger.cpp +4 −0 Original line number Diff line number Diff line Loading @@ -2476,6 +2476,10 @@ bool SurfaceFlinger::commit(PhysicalDisplayId pacesetterId, if (pacesetterFrameTarget.isFramePending()) { if (mBackpressureGpuComposition || pacesetterFrameTarget.didMissHwcFrame()) { if (FlagManager::getInstance().vrr_config()) { mScheduler->getVsyncSchedule()->getTracker().onFrameMissed( pacesetterFrameTarget.expectedPresentTime()); } scheduleCommit(FrameHint::kNone); return false; } Loading