Loading services/surfaceflinger/Scheduler/Scheduler.cpp +5 −1 Original line number Original line Diff line number Diff line Loading @@ -418,7 +418,11 @@ void Scheduler::setRenderRate(Fps renderFrameRate) { ALOGV("%s %s (%s)", __func__, to_string(mode.fps).c_str(), ALOGV("%s %s (%s)", __func__, to_string(mode.fps).c_str(), to_string(mode.modePtr->getFps()).c_str()); to_string(mode.modePtr->getFps()).c_str()); mVsyncSchedule->getTracker().setRenderRate(renderFrameRate); const auto divisor = RefreshRateSelector::getFrameRateDivisor(mode.modePtr->getFps(), mode.fps); LOG_ALWAYS_FATAL_IF(divisor == 0, "%s <> %s -- not divisors", to_string(mode.fps).c_str(), to_string(mode.fps).c_str()); mVsyncSchedule->getTracker().setDivisor(static_cast<unsigned>(divisor)); } } void Scheduler::resync() { void Scheduler::resync() { Loading services/surfaceflinger/Scheduler/VSyncPredictor.cpp +6 −19 Original line number Original line Diff line number Diff line Loading @@ -272,26 +272,13 @@ nsecs_t VSyncPredictor::nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const { // update the mLastVsyncSequence for reference point // update the mLastVsyncSequence for reference point mLastVsyncSequence = getVsyncSequenceLocked(timePoint); mLastVsyncSequence = getVsyncSequenceLocked(timePoint); const auto renderRatePhase = [&]() REQUIRES(mMutex) -> int { const auto mod = mLastVsyncSequence->seq % mDivisor; if (!mRenderRate) return 0; if (mod == 0) { const auto divisor = RefreshRateSelector::getFrameRateDivisor(Fps::fromPeriodNsecs(mIdealPeriod), *mRenderRate); if (divisor <= 1) return 0; const int mod = mLastVsyncSequence->seq % divisor; if (mod == 0) return 0; return divisor - mod; }(); if (renderRatePhase == 0) { return mLastVsyncSequence->vsyncTime; return mLastVsyncSequence->vsyncTime; } } auto const [slope, intercept] = getVSyncPredictionModelLocked(); auto const [slope, intercept] = getVSyncPredictionModelLocked(); const auto approximateNextVsync = mLastVsyncSequence->vsyncTime + slope * renderRatePhase; const auto approximateNextVsync = mLastVsyncSequence->vsyncTime + slope * (mDivisor - mod); return nextAnticipatedVSyncTimeFromLocked(approximateNextVsync - slope / 2); return nextAnticipatedVSyncTimeFromLocked(approximateNextVsync - slope / 2); } } Loading Loading @@ -330,10 +317,10 @@ bool VSyncPredictor::isVSyncInPhaseLocked(nsecs_t timePoint, unsigned divisor) c return vsyncSequence.seq % divisor == 0; return vsyncSequence.seq % divisor == 0; } } void VSyncPredictor::setRenderRate(Fps fps) { void VSyncPredictor::setDivisor(unsigned divisor) { ALOGV("%s: %s", __func__, to_string(fps).c_str()); ALOGV("%s: %d", __func__, divisor); std::lock_guard lock(mMutex); std::lock_guard lock(mMutex); mRenderRate = fps; mDivisor = divisor; } } VSyncPredictor::Model VSyncPredictor::getVSyncPredictionModel() const { VSyncPredictor::Model VSyncPredictor::getVSyncPredictionModel() const { Loading services/surfaceflinger/Scheduler/VSyncPredictor.h +2 −2 Original line number Original line Diff line number Diff line Loading @@ -67,7 +67,7 @@ public: bool isVSyncInPhase(nsecs_t timePoint, Fps frameRate) const final EXCLUDES(mMutex); bool isVSyncInPhase(nsecs_t timePoint, Fps frameRate) const final EXCLUDES(mMutex); void setRenderRate(Fps) final EXCLUDES(mMutex); void setDivisor(unsigned divisor) final EXCLUDES(mMutex); void dump(std::string& result) const final EXCLUDES(mMutex); void dump(std::string& result) const final EXCLUDES(mMutex); Loading Loading @@ -106,7 +106,7 @@ private: size_t mLastTimestampIndex GUARDED_BY(mMutex) = 0; size_t mLastTimestampIndex GUARDED_BY(mMutex) = 0; std::vector<nsecs_t> mTimestamps GUARDED_BY(mMutex); std::vector<nsecs_t> mTimestamps GUARDED_BY(mMutex); std::optional<Fps> mRenderRate GUARDED_BY(mMutex); unsigned mDivisor GUARDED_BY(mMutex) = 1; mutable std::optional<VsyncSequence> mLastVsyncSequence GUARDED_BY(mMutex); mutable std::optional<VsyncSequence> mLastVsyncSequence GUARDED_BY(mMutex); }; }; Loading services/surfaceflinger/Scheduler/VSyncTracker.h +4 −5 Original line number Original line Diff line number Diff line Loading @@ -80,16 +80,15 @@ public: virtual bool isVSyncInPhase(nsecs_t timePoint, Fps frameRate) const = 0; virtual bool isVSyncInPhase(nsecs_t timePoint, Fps frameRate) const = 0; /* /* * Sets a render rate on the tracker. If the render rate is not a divisor * Sets a divisor on the rate (which is a multiplier of the period). * of the period, the render rate is ignored until the period changes. * The tracker will continue to track the vsync timeline and expect it * The tracker will continue to track the vsync timeline and expect it * to match the current period, however, nextAnticipatedVSyncTimeFrom will * to match the current period, however, nextAnticipatedVSyncTimeFrom will * return vsyncs according to the render rate set. Setting a render rate is useful * return vsyncs according to the divisor set. Setting a divisor is useful * when a display is running at 120Hz but the render frame rate is 60Hz. * when a display is running at 120Hz but the render frame rate is 60Hz. * * * \param [in] Fps The render rate the tracker should operate at. * \param [in] divisor The rate divisor the tracker should operate at. */ */ virtual void setRenderRate(Fps) = 0; virtual void setDivisor(unsigned divisor) = 0; virtual void dump(std::string& result) const = 0; virtual void dump(std::string& result) const = 0; Loading services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h +1 −1 Original line number Original line Diff line number Diff line Loading @@ -100,7 +100,7 @@ public: return true; return true; } } void setRenderRate(Fps) override {} void setDivisor(unsigned) override {} nsecs_t nextVSyncTime(nsecs_t timePoint) const { nsecs_t nextVSyncTime(nsecs_t timePoint) const { if (timePoint % mPeriod == 0) { if (timePoint % mPeriod == 0) { Loading Loading
services/surfaceflinger/Scheduler/Scheduler.cpp +5 −1 Original line number Original line Diff line number Diff line Loading @@ -418,7 +418,11 @@ void Scheduler::setRenderRate(Fps renderFrameRate) { ALOGV("%s %s (%s)", __func__, to_string(mode.fps).c_str(), ALOGV("%s %s (%s)", __func__, to_string(mode.fps).c_str(), to_string(mode.modePtr->getFps()).c_str()); to_string(mode.modePtr->getFps()).c_str()); mVsyncSchedule->getTracker().setRenderRate(renderFrameRate); const auto divisor = RefreshRateSelector::getFrameRateDivisor(mode.modePtr->getFps(), mode.fps); LOG_ALWAYS_FATAL_IF(divisor == 0, "%s <> %s -- not divisors", to_string(mode.fps).c_str(), to_string(mode.fps).c_str()); mVsyncSchedule->getTracker().setDivisor(static_cast<unsigned>(divisor)); } } void Scheduler::resync() { void Scheduler::resync() { Loading
services/surfaceflinger/Scheduler/VSyncPredictor.cpp +6 −19 Original line number Original line Diff line number Diff line Loading @@ -272,26 +272,13 @@ nsecs_t VSyncPredictor::nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const { // update the mLastVsyncSequence for reference point // update the mLastVsyncSequence for reference point mLastVsyncSequence = getVsyncSequenceLocked(timePoint); mLastVsyncSequence = getVsyncSequenceLocked(timePoint); const auto renderRatePhase = [&]() REQUIRES(mMutex) -> int { const auto mod = mLastVsyncSequence->seq % mDivisor; if (!mRenderRate) return 0; if (mod == 0) { const auto divisor = RefreshRateSelector::getFrameRateDivisor(Fps::fromPeriodNsecs(mIdealPeriod), *mRenderRate); if (divisor <= 1) return 0; const int mod = mLastVsyncSequence->seq % divisor; if (mod == 0) return 0; return divisor - mod; }(); if (renderRatePhase == 0) { return mLastVsyncSequence->vsyncTime; return mLastVsyncSequence->vsyncTime; } } auto const [slope, intercept] = getVSyncPredictionModelLocked(); auto const [slope, intercept] = getVSyncPredictionModelLocked(); const auto approximateNextVsync = mLastVsyncSequence->vsyncTime + slope * renderRatePhase; const auto approximateNextVsync = mLastVsyncSequence->vsyncTime + slope * (mDivisor - mod); return nextAnticipatedVSyncTimeFromLocked(approximateNextVsync - slope / 2); return nextAnticipatedVSyncTimeFromLocked(approximateNextVsync - slope / 2); } } Loading Loading @@ -330,10 +317,10 @@ bool VSyncPredictor::isVSyncInPhaseLocked(nsecs_t timePoint, unsigned divisor) c return vsyncSequence.seq % divisor == 0; return vsyncSequence.seq % divisor == 0; } } void VSyncPredictor::setRenderRate(Fps fps) { void VSyncPredictor::setDivisor(unsigned divisor) { ALOGV("%s: %s", __func__, to_string(fps).c_str()); ALOGV("%s: %d", __func__, divisor); std::lock_guard lock(mMutex); std::lock_guard lock(mMutex); mRenderRate = fps; mDivisor = divisor; } } VSyncPredictor::Model VSyncPredictor::getVSyncPredictionModel() const { VSyncPredictor::Model VSyncPredictor::getVSyncPredictionModel() const { Loading
services/surfaceflinger/Scheduler/VSyncPredictor.h +2 −2 Original line number Original line Diff line number Diff line Loading @@ -67,7 +67,7 @@ public: bool isVSyncInPhase(nsecs_t timePoint, Fps frameRate) const final EXCLUDES(mMutex); bool isVSyncInPhase(nsecs_t timePoint, Fps frameRate) const final EXCLUDES(mMutex); void setRenderRate(Fps) final EXCLUDES(mMutex); void setDivisor(unsigned divisor) final EXCLUDES(mMutex); void dump(std::string& result) const final EXCLUDES(mMutex); void dump(std::string& result) const final EXCLUDES(mMutex); Loading Loading @@ -106,7 +106,7 @@ private: size_t mLastTimestampIndex GUARDED_BY(mMutex) = 0; size_t mLastTimestampIndex GUARDED_BY(mMutex) = 0; std::vector<nsecs_t> mTimestamps GUARDED_BY(mMutex); std::vector<nsecs_t> mTimestamps GUARDED_BY(mMutex); std::optional<Fps> mRenderRate GUARDED_BY(mMutex); unsigned mDivisor GUARDED_BY(mMutex) = 1; mutable std::optional<VsyncSequence> mLastVsyncSequence GUARDED_BY(mMutex); mutable std::optional<VsyncSequence> mLastVsyncSequence GUARDED_BY(mMutex); }; }; Loading
services/surfaceflinger/Scheduler/VSyncTracker.h +4 −5 Original line number Original line Diff line number Diff line Loading @@ -80,16 +80,15 @@ public: virtual bool isVSyncInPhase(nsecs_t timePoint, Fps frameRate) const = 0; virtual bool isVSyncInPhase(nsecs_t timePoint, Fps frameRate) const = 0; /* /* * Sets a render rate on the tracker. If the render rate is not a divisor * Sets a divisor on the rate (which is a multiplier of the period). * of the period, the render rate is ignored until the period changes. * The tracker will continue to track the vsync timeline and expect it * The tracker will continue to track the vsync timeline and expect it * to match the current period, however, nextAnticipatedVSyncTimeFrom will * to match the current period, however, nextAnticipatedVSyncTimeFrom will * return vsyncs according to the render rate set. Setting a render rate is useful * return vsyncs according to the divisor set. Setting a divisor is useful * when a display is running at 120Hz but the render frame rate is 60Hz. * when a display is running at 120Hz but the render frame rate is 60Hz. * * * \param [in] Fps The render rate the tracker should operate at. * \param [in] divisor The rate divisor the tracker should operate at. */ */ virtual void setRenderRate(Fps) = 0; virtual void setDivisor(unsigned divisor) = 0; virtual void dump(std::string& result) const = 0; virtual void dump(std::string& result) const = 0; Loading
services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h +1 −1 Original line number Original line Diff line number Diff line Loading @@ -100,7 +100,7 @@ public: return true; return true; } } void setRenderRate(Fps) override {} void setDivisor(unsigned) override {} nsecs_t nextVSyncTime(nsecs_t timePoint) const { nsecs_t nextVSyncTime(nsecs_t timePoint) const { if (timePoint % mPeriod == 0) { if (timePoint % mPeriod == 0) { Loading