Loading services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +30 −68 Original line number Diff line number Diff line Loading @@ -38,6 +38,8 @@ namespace android::scheduler { namespace { constexpr RefreshRateConfigs::GlobalSignals kNoSignals; std::string formatLayerInfo(const RefreshRateConfigs::LayerRequirement& layer, float weight) { return base::StringPrintf("%s (type=%s, weight=%.2f seamlessness=%s) %s", layer.name.c_str(), ftl::enum_string(layer.vote).c_str(), weight, Loading Loading @@ -235,63 +237,26 @@ struct RefreshRateScore { float score; }; RefreshRate RefreshRateConfigs::getBestRefreshRate(const std::vector<LayerRequirement>& layers, GlobalSignals globalSignals, GlobalSignals* outSignalsConsidered) const { auto RefreshRateConfigs::getBestRefreshRate(const std::vector<LayerRequirement>& layers, GlobalSignals signals) const -> std::pair<RefreshRate, GlobalSignals> { std::lock_guard lock(mLock); if (auto cached = getCachedBestRefreshRate(layers, globalSignals, outSignalsConsidered)) { return *cached; if (mGetBestRefreshRateCache && mGetBestRefreshRateCache->arguments == std::make_pair(layers, signals)) { return mGetBestRefreshRateCache->result; } GlobalSignals signalsConsidered; RefreshRate result = getBestRefreshRateLocked(layers, globalSignals, &signalsConsidered); lastBestRefreshRateInvocation.emplace( GetBestRefreshRateInvocation{.layerRequirements = layers, .globalSignals = globalSignals, .outSignalsConsidered = signalsConsidered, .resultingBestRefreshRate = result}); if (outSignalsConsidered) { *outSignalsConsidered = signalsConsidered; } const auto result = getBestRefreshRateLocked(layers, signals); mGetBestRefreshRateCache = GetBestRefreshRateCache{{layers, signals}, result}; return result; } std::optional<RefreshRate> RefreshRateConfigs::getCachedBestRefreshRate( const std::vector<LayerRequirement>& layers, GlobalSignals globalSignals, GlobalSignals* outSignalsConsidered) const { const bool sameAsLastCall = lastBestRefreshRateInvocation && lastBestRefreshRateInvocation->layerRequirements == layers && lastBestRefreshRateInvocation->globalSignals == globalSignals; if (sameAsLastCall) { if (outSignalsConsidered) { *outSignalsConsidered = lastBestRefreshRateInvocation->outSignalsConsidered; } return lastBestRefreshRateInvocation->resultingBestRefreshRate; } return {}; } RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( const std::vector<LayerRequirement>& layers, GlobalSignals globalSignals, GlobalSignals* outSignalsConsidered) const { auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequirement>& layers, GlobalSignals signals) const -> std::pair<RefreshRate, GlobalSignals> { ATRACE_CALL(); ALOGV("getBestRefreshRate %zu layers", layers.size()); if (outSignalsConsidered) *outSignalsConsidered = {}; const auto setTouchConsidered = [&] { if (outSignalsConsidered) { outSignalsConsidered->touch = true; } }; const auto setIdleConsidered = [&] { if (outSignalsConsidered) { outSignalsConsidered->idle = true; } }; ALOGV("%s: %zu layers", __func__, layers.size()); int noVoteLayers = 0; int minVoteLayers = 0; Loading @@ -301,6 +266,7 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( int explicitExact = 0; float maxExplicitWeight = 0; int seamedFocusedLayers = 0; for (const auto& layer : layers) { switch (layer.vote) { case LayerVoteType::NoVote: Loading Loading @@ -349,10 +315,9 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( // Consider the touch event if there are no Explicit* layers. Otherwise wait until after we've // selected a refresh rate to see if we should apply touch boost. if (globalSignals.touch && !hasExplicitVoteLayers) { if (signals.touch && !hasExplicitVoteLayers) { ALOGV("TouchBoost - choose %s", getMaxRefreshRateByPolicyLocked().getName().c_str()); setTouchConsidered(); return getMaxRefreshRateByPolicyLocked(anchorGroup); return {getMaxRefreshRateByPolicyLocked(anchorGroup), GlobalSignals{.touch = true}}; } // If the primary range consists of a single refresh rate then we can only Loading @@ -361,23 +326,21 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( const bool primaryRangeIsSingleRate = isApproxEqual(policy->primaryRange.min, policy->primaryRange.max); if (!globalSignals.touch && globalSignals.idle && !(primaryRangeIsSingleRate && hasExplicitVoteLayers)) { if (!signals.touch && signals.idle && !(primaryRangeIsSingleRate && hasExplicitVoteLayers)) { ALOGV("Idle - choose %s", getMinRefreshRateByPolicyLocked().getName().c_str()); setIdleConsidered(); return getMinRefreshRateByPolicyLocked(); return {getMinRefreshRateByPolicyLocked(), GlobalSignals{.idle = true}}; } if (layers.empty() || noVoteLayers == layers.size()) { const auto& refreshRate = getMaxRefreshRateByPolicyLocked(anchorGroup); ALOGV("no layers with votes - choose %s", refreshRate.getName().c_str()); return refreshRate; return {refreshRate, kNoSignals}; } // Only if all layers want Min we should return Min if (noVoteLayers + minVoteLayers == layers.size()) { ALOGV("all layers Min - choose %s", getMinRefreshRateByPolicyLocked().getName().c_str()); return getMinRefreshRateByPolicyLocked(); return {getMinRefreshRateByPolicyLocked(), kNoSignals}; } // Find the best refresh rate based on score Loading Loading @@ -466,9 +429,9 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( [](RefreshRateScore score) { return score.score == 0; })) { const auto& refreshRate = getMaxRefreshRateByPolicyLocked(anchorGroup); ALOGV("layers not scored - choose %s", refreshRate.getName().c_str()); return refreshRate; return {refreshRate, kNoSignals}; } else { return *bestRefreshRate; return {*bestRefreshRate, kNoSignals}; } } Loading @@ -490,14 +453,13 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( using fps_approx_ops::operator<; if (globalSignals.touch && explicitDefaultVoteLayers == 0 && touchBoostForExplicitExact && if (signals.touch && explicitDefaultVoteLayers == 0 && touchBoostForExplicitExact && bestRefreshRate->getFps() < touchRefreshRate.getFps()) { setTouchConsidered(); ALOGV("TouchBoost - choose %s", touchRefreshRate.getName().c_str()); return touchRefreshRate; return {touchRefreshRate, GlobalSignals{.touch = true}}; } return *bestRefreshRate; return {*bestRefreshRate, kNoSignals}; } std::unordered_map<uid_t, std::vector<const RefreshRateConfigs::LayerRequirement*>> Loading Loading @@ -699,7 +661,7 @@ void RefreshRateConfigs::setCurrentModeId(DisplayModeId modeId) { // Invalidate the cached invocation to getBestRefreshRate. This forces // the refresh rate to be recomputed on the next call to getBestRefreshRate. lastBestRefreshRateInvocation.reset(); mGetBestRefreshRateCache.reset(); mCurrentRefreshRate = mRefreshRates.at(modeId).get(); } Loading Loading @@ -741,7 +703,7 @@ void RefreshRateConfigs::updateDisplayModes(const DisplayModes& modes, // Invalidate the cached invocation to getBestRefreshRate. This forces // the refresh rate to be recomputed on the next call to getBestRefreshRate. lastBestRefreshRateInvocation.reset(); mGetBestRefreshRateCache.reset(); mRefreshRates.clear(); for (const auto& mode : modes) { Loading Loading @@ -800,7 +762,7 @@ status_t RefreshRateConfigs::setDisplayManagerPolicy(const Policy& policy) { ALOGE("Invalid refresh rate policy: %s", policy.toString().c_str()); return BAD_VALUE; } lastBestRefreshRateInvocation.reset(); mGetBestRefreshRateCache.reset(); Policy previousPolicy = *getCurrentPolicyLocked(); mDisplayManagerPolicy = policy; if (*getCurrentPolicyLocked() == previousPolicy) { Loading @@ -815,7 +777,7 @@ status_t RefreshRateConfigs::setOverridePolicy(const std::optional<Policy>& poli if (policy && !isPolicyValidLocked(*policy)) { return BAD_VALUE; } lastBestRefreshRateInvocation.reset(); mGetBestRefreshRateCache.reset(); Policy previousPolicy = *getCurrentPolicyLocked(); mOverridePolicy = policy; if (*getCurrentPolicyLocked() == previousPolicy) { Loading services/surfaceflinger/Scheduler/RefreshRateConfigs.h +11 −19 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <numeric> #include <optional> #include <type_traits> #include <utility> #include <android-base/stringprintf.h> #include <gui/DisplayEventReceiver.h> Loading Loading @@ -249,11 +250,10 @@ public: } }; // Returns the refresh rate that best fits the given layers. outSignalsConsidered returns // whether the refresh rate was chosen based on touch boost and/or idle timer. RefreshRate getBestRefreshRate(const std::vector<LayerRequirement>&, GlobalSignals, GlobalSignals* outSignalsConsidered = nullptr) const EXCLUDES(mLock); // Returns the refresh rate that best fits the given layers, and whether the refresh rate was // chosen based on touch boost and/or idle timer. std::pair<RefreshRate, GlobalSignals> getBestRefreshRate(const std::vector<LayerRequirement>&, GlobalSignals) const EXCLUDES(mLock); FpsRange getSupportedRefreshRateRange() const EXCLUDES(mLock) { std::lock_guard lock(mLock); Loading Loading @@ -403,13 +403,8 @@ private: const std::function<bool(const RefreshRate&)>& shouldAddRefreshRate, std::vector<const RefreshRate*>* outRefreshRates) REQUIRES(mLock); std::optional<RefreshRate> getCachedBestRefreshRate(const std::vector<LayerRequirement>&, GlobalSignals, GlobalSignals* outSignalsConsidered) const REQUIRES(mLock); RefreshRate getBestRefreshRateLocked(const std::vector<LayerRequirement>&, GlobalSignals, GlobalSignals* outSignalsConsidered) const REQUIRES(mLock); std::pair<RefreshRate, GlobalSignals> getBestRefreshRateLocked( const std::vector<LayerRequirement>&, GlobalSignals) const REQUIRES(mLock); // Returns the refresh rate with the highest score in the collection specified from begin // to end. If there are more than one with the same highest refresh rate, the first one is Loading Loading @@ -497,14 +492,11 @@ private: const Config mConfig; bool mSupportsFrameRateOverrideByContent; struct GetBestRefreshRateInvocation { std::vector<LayerRequirement> layerRequirements; GlobalSignals globalSignals; GlobalSignals outSignalsConsidered; RefreshRate resultingBestRefreshRate; struct GetBestRefreshRateCache { std::pair<std::vector<LayerRequirement>, GlobalSignals> arguments; std::pair<RefreshRate, GlobalSignals> result; }; mutable std::optional<GetBestRefreshRateInvocation> lastBestRefreshRateInvocation GUARDED_BY(mLock); mutable std::optional<GetBestRefreshRateCache> mGetBestRefreshRateCache GUARDED_BY(mLock); // Declare mIdleTimer last to ensure its thread joins before the mutex/callbacks are destroyed. std::mutex mIdleTimerCallbacksMutex; Loading services/surfaceflinger/Scheduler/Scheduler.cpp +25 −23 Original line number Diff line number Diff line Loading @@ -537,18 +537,19 @@ void Scheduler::chooseRefreshRateForContent() { ATRACE_CALL(); const auto refreshRateConfigs = holdRefreshRateConfigs(); scheduler::LayerHistory::Summary summary = mLayerHistory.summarize(*refreshRateConfigs, systemTime()); scheduler::RefreshRateConfigs::GlobalSignals consideredSignals; DisplayModePtr newMode; GlobalSignals consideredSignals; bool frameRateChanged; bool frameRateOverridesChanged; const auto refreshRateConfigs = holdRefreshRateConfigs(); LayerHistory::Summary summary = mLayerHistory.summarize(*refreshRateConfigs, systemTime()); { std::lock_guard<std::mutex> lock(mPolicyLock); mPolicy.contentRequirements = summary; mPolicy.contentRequirements = std::move(summary); newMode = calculateRefreshRateModeId(&consideredSignals); std::tie(newMode, consideredSignals) = chooseDisplayMode(); frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps()); if (mPolicy.mode == newMode) { Loading Loading @@ -678,8 +679,7 @@ void Scheduler::dumpVsync(std::string& out) const { mVsyncSchedule->dump(out); } bool Scheduler::updateFrameRateOverrides( scheduler::RefreshRateConfigs::GlobalSignals consideredSignals, Fps displayRefreshRate) { bool Scheduler::updateFrameRateOverrides(GlobalSignals consideredSignals, Fps displayRefreshRate) { const auto refreshRateConfigs = holdRefreshRateConfigs(); if (!refreshRateConfigs->supportsFrameRateOverrideByContent()) { return false; Loading @@ -697,9 +697,11 @@ bool Scheduler::updateFrameRateOverrides( template <class T> bool Scheduler::handleTimerStateChanged(T* currentState, T newState) { DisplayModePtr newMode; GlobalSignals consideredSignals; bool refreshRateChanged = false; bool frameRateOverridesChanged; scheduler::RefreshRateConfigs::GlobalSignals consideredSignals; const auto refreshRateConfigs = holdRefreshRateConfigs(); { std::lock_guard<std::mutex> lock(mPolicyLock); Loading @@ -707,7 +709,7 @@ bool Scheduler::handleTimerStateChanged(T* currentState, T newState) { return false; } *currentState = newState; newMode = calculateRefreshRateModeId(&consideredSignals); std::tie(newMode, consideredSignals) = chooseDisplayMode(); frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps()); if (mPolicy.mode == newMode) { // We don't need to change the display mode, but we might need to send an event Loading @@ -733,33 +735,33 @@ bool Scheduler::handleTimerStateChanged(T* currentState, T newState) { return consideredSignals.touch; } DisplayModePtr Scheduler::calculateRefreshRateModeId( scheduler::RefreshRateConfigs::GlobalSignals* consideredSignals) { auto Scheduler::chooseDisplayMode() -> std::pair<DisplayModePtr, GlobalSignals> { ATRACE_CALL(); if (consideredSignals) *consideredSignals = {}; const auto refreshRateConfigs = holdRefreshRateConfigs(); const auto configs = holdRefreshRateConfigs(); // If Display Power is not in normal operation we want to be in performance mode. When coming // back to normal mode, a grace period is given with DisplayPowerTimer. if (mDisplayPowerTimer && (!mPolicy.isDisplayPowerStateNormal || mPolicy.displayPowerTimer == TimerState::Reset)) { return refreshRateConfigs->getMaxRefreshRateByPolicy().getMode(); constexpr GlobalSignals kNoSignals; return {configs->getMaxRefreshRateByPolicy().getMode(), kNoSignals}; } const bool touchActive = mTouchTimer && mPolicy.touch == TouchState::Active; const bool idle = mPolicy.idleTimer == TimerState::Expired; const GlobalSignals signals{.touch = mTouchTimer && mPolicy.touch == TouchState::Active, .idle = mPolicy.idleTimer == TimerState::Expired}; const auto [refreshRate, consideredSignals] = configs->getBestRefreshRate(mPolicy.contentRequirements, signals); return refreshRateConfigs ->getBestRefreshRate(mPolicy.contentRequirements, {.touch = touchActive, .idle = idle}, consideredSignals) .getMode(); return {refreshRate.getMode(), consideredSignals}; } DisplayModePtr Scheduler::getPreferredDisplayMode() { std::lock_guard<std::mutex> lock(mPolicyLock); // Make sure that the default mode ID is first updated, before returned. // Make sure the stored mode is up to date. if (mPolicy.mode) { mPolicy.mode = calculateRefreshRateModeId(); mPolicy.mode = chooseDisplayMode().first; } return mPolicy.mode; } Loading services/surfaceflinger/Scheduler/Scheduler.h +6 −7 Original line number Diff line number Diff line Loading @@ -269,15 +269,14 @@ private: void setVsyncPeriod(nsecs_t period); // This function checks whether individual features that are affecting the refresh rate // selection were initialized, prioritizes them, and calculates the DisplayModeId // for the suggested refresh rate. DisplayModePtr calculateRefreshRateModeId( RefreshRateConfigs::GlobalSignals* consideredSignals = nullptr) REQUIRES(mPolicyLock); using GlobalSignals = RefreshRateConfigs::GlobalSignals; // Returns the display mode that fulfills the policy, and the signals that were considered. std::pair<DisplayModePtr, GlobalSignals> chooseDisplayMode() REQUIRES(mPolicyLock); bool updateFrameRateOverrides(GlobalSignals, Fps displayRefreshRate) REQUIRES(mPolicyLock); void dispatchCachedReportedMode() REQUIRES(mPolicyLock) EXCLUDES(mRefreshRateConfigsLock); bool updateFrameRateOverrides(RefreshRateConfigs::GlobalSignals, Fps displayRefreshRate) REQUIRES(mPolicyLock); impl::EventThread::ThrottleVsyncCallback makeThrottleVsyncCallback() const EXCLUDES(mRefreshRateConfigsLock); Loading services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +260 −273 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +30 −68 Original line number Diff line number Diff line Loading @@ -38,6 +38,8 @@ namespace android::scheduler { namespace { constexpr RefreshRateConfigs::GlobalSignals kNoSignals; std::string formatLayerInfo(const RefreshRateConfigs::LayerRequirement& layer, float weight) { return base::StringPrintf("%s (type=%s, weight=%.2f seamlessness=%s) %s", layer.name.c_str(), ftl::enum_string(layer.vote).c_str(), weight, Loading Loading @@ -235,63 +237,26 @@ struct RefreshRateScore { float score; }; RefreshRate RefreshRateConfigs::getBestRefreshRate(const std::vector<LayerRequirement>& layers, GlobalSignals globalSignals, GlobalSignals* outSignalsConsidered) const { auto RefreshRateConfigs::getBestRefreshRate(const std::vector<LayerRequirement>& layers, GlobalSignals signals) const -> std::pair<RefreshRate, GlobalSignals> { std::lock_guard lock(mLock); if (auto cached = getCachedBestRefreshRate(layers, globalSignals, outSignalsConsidered)) { return *cached; if (mGetBestRefreshRateCache && mGetBestRefreshRateCache->arguments == std::make_pair(layers, signals)) { return mGetBestRefreshRateCache->result; } GlobalSignals signalsConsidered; RefreshRate result = getBestRefreshRateLocked(layers, globalSignals, &signalsConsidered); lastBestRefreshRateInvocation.emplace( GetBestRefreshRateInvocation{.layerRequirements = layers, .globalSignals = globalSignals, .outSignalsConsidered = signalsConsidered, .resultingBestRefreshRate = result}); if (outSignalsConsidered) { *outSignalsConsidered = signalsConsidered; } const auto result = getBestRefreshRateLocked(layers, signals); mGetBestRefreshRateCache = GetBestRefreshRateCache{{layers, signals}, result}; return result; } std::optional<RefreshRate> RefreshRateConfigs::getCachedBestRefreshRate( const std::vector<LayerRequirement>& layers, GlobalSignals globalSignals, GlobalSignals* outSignalsConsidered) const { const bool sameAsLastCall = lastBestRefreshRateInvocation && lastBestRefreshRateInvocation->layerRequirements == layers && lastBestRefreshRateInvocation->globalSignals == globalSignals; if (sameAsLastCall) { if (outSignalsConsidered) { *outSignalsConsidered = lastBestRefreshRateInvocation->outSignalsConsidered; } return lastBestRefreshRateInvocation->resultingBestRefreshRate; } return {}; } RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( const std::vector<LayerRequirement>& layers, GlobalSignals globalSignals, GlobalSignals* outSignalsConsidered) const { auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequirement>& layers, GlobalSignals signals) const -> std::pair<RefreshRate, GlobalSignals> { ATRACE_CALL(); ALOGV("getBestRefreshRate %zu layers", layers.size()); if (outSignalsConsidered) *outSignalsConsidered = {}; const auto setTouchConsidered = [&] { if (outSignalsConsidered) { outSignalsConsidered->touch = true; } }; const auto setIdleConsidered = [&] { if (outSignalsConsidered) { outSignalsConsidered->idle = true; } }; ALOGV("%s: %zu layers", __func__, layers.size()); int noVoteLayers = 0; int minVoteLayers = 0; Loading @@ -301,6 +266,7 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( int explicitExact = 0; float maxExplicitWeight = 0; int seamedFocusedLayers = 0; for (const auto& layer : layers) { switch (layer.vote) { case LayerVoteType::NoVote: Loading Loading @@ -349,10 +315,9 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( // Consider the touch event if there are no Explicit* layers. Otherwise wait until after we've // selected a refresh rate to see if we should apply touch boost. if (globalSignals.touch && !hasExplicitVoteLayers) { if (signals.touch && !hasExplicitVoteLayers) { ALOGV("TouchBoost - choose %s", getMaxRefreshRateByPolicyLocked().getName().c_str()); setTouchConsidered(); return getMaxRefreshRateByPolicyLocked(anchorGroup); return {getMaxRefreshRateByPolicyLocked(anchorGroup), GlobalSignals{.touch = true}}; } // If the primary range consists of a single refresh rate then we can only Loading @@ -361,23 +326,21 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( const bool primaryRangeIsSingleRate = isApproxEqual(policy->primaryRange.min, policy->primaryRange.max); if (!globalSignals.touch && globalSignals.idle && !(primaryRangeIsSingleRate && hasExplicitVoteLayers)) { if (!signals.touch && signals.idle && !(primaryRangeIsSingleRate && hasExplicitVoteLayers)) { ALOGV("Idle - choose %s", getMinRefreshRateByPolicyLocked().getName().c_str()); setIdleConsidered(); return getMinRefreshRateByPolicyLocked(); return {getMinRefreshRateByPolicyLocked(), GlobalSignals{.idle = true}}; } if (layers.empty() || noVoteLayers == layers.size()) { const auto& refreshRate = getMaxRefreshRateByPolicyLocked(anchorGroup); ALOGV("no layers with votes - choose %s", refreshRate.getName().c_str()); return refreshRate; return {refreshRate, kNoSignals}; } // Only if all layers want Min we should return Min if (noVoteLayers + minVoteLayers == layers.size()) { ALOGV("all layers Min - choose %s", getMinRefreshRateByPolicyLocked().getName().c_str()); return getMinRefreshRateByPolicyLocked(); return {getMinRefreshRateByPolicyLocked(), kNoSignals}; } // Find the best refresh rate based on score Loading Loading @@ -466,9 +429,9 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( [](RefreshRateScore score) { return score.score == 0; })) { const auto& refreshRate = getMaxRefreshRateByPolicyLocked(anchorGroup); ALOGV("layers not scored - choose %s", refreshRate.getName().c_str()); return refreshRate; return {refreshRate, kNoSignals}; } else { return *bestRefreshRate; return {*bestRefreshRate, kNoSignals}; } } Loading @@ -490,14 +453,13 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( using fps_approx_ops::operator<; if (globalSignals.touch && explicitDefaultVoteLayers == 0 && touchBoostForExplicitExact && if (signals.touch && explicitDefaultVoteLayers == 0 && touchBoostForExplicitExact && bestRefreshRate->getFps() < touchRefreshRate.getFps()) { setTouchConsidered(); ALOGV("TouchBoost - choose %s", touchRefreshRate.getName().c_str()); return touchRefreshRate; return {touchRefreshRate, GlobalSignals{.touch = true}}; } return *bestRefreshRate; return {*bestRefreshRate, kNoSignals}; } std::unordered_map<uid_t, std::vector<const RefreshRateConfigs::LayerRequirement*>> Loading Loading @@ -699,7 +661,7 @@ void RefreshRateConfigs::setCurrentModeId(DisplayModeId modeId) { // Invalidate the cached invocation to getBestRefreshRate. This forces // the refresh rate to be recomputed on the next call to getBestRefreshRate. lastBestRefreshRateInvocation.reset(); mGetBestRefreshRateCache.reset(); mCurrentRefreshRate = mRefreshRates.at(modeId).get(); } Loading Loading @@ -741,7 +703,7 @@ void RefreshRateConfigs::updateDisplayModes(const DisplayModes& modes, // Invalidate the cached invocation to getBestRefreshRate. This forces // the refresh rate to be recomputed on the next call to getBestRefreshRate. lastBestRefreshRateInvocation.reset(); mGetBestRefreshRateCache.reset(); mRefreshRates.clear(); for (const auto& mode : modes) { Loading Loading @@ -800,7 +762,7 @@ status_t RefreshRateConfigs::setDisplayManagerPolicy(const Policy& policy) { ALOGE("Invalid refresh rate policy: %s", policy.toString().c_str()); return BAD_VALUE; } lastBestRefreshRateInvocation.reset(); mGetBestRefreshRateCache.reset(); Policy previousPolicy = *getCurrentPolicyLocked(); mDisplayManagerPolicy = policy; if (*getCurrentPolicyLocked() == previousPolicy) { Loading @@ -815,7 +777,7 @@ status_t RefreshRateConfigs::setOverridePolicy(const std::optional<Policy>& poli if (policy && !isPolicyValidLocked(*policy)) { return BAD_VALUE; } lastBestRefreshRateInvocation.reset(); mGetBestRefreshRateCache.reset(); Policy previousPolicy = *getCurrentPolicyLocked(); mOverridePolicy = policy; if (*getCurrentPolicyLocked() == previousPolicy) { Loading
services/surfaceflinger/Scheduler/RefreshRateConfigs.h +11 −19 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <numeric> #include <optional> #include <type_traits> #include <utility> #include <android-base/stringprintf.h> #include <gui/DisplayEventReceiver.h> Loading Loading @@ -249,11 +250,10 @@ public: } }; // Returns the refresh rate that best fits the given layers. outSignalsConsidered returns // whether the refresh rate was chosen based on touch boost and/or idle timer. RefreshRate getBestRefreshRate(const std::vector<LayerRequirement>&, GlobalSignals, GlobalSignals* outSignalsConsidered = nullptr) const EXCLUDES(mLock); // Returns the refresh rate that best fits the given layers, and whether the refresh rate was // chosen based on touch boost and/or idle timer. std::pair<RefreshRate, GlobalSignals> getBestRefreshRate(const std::vector<LayerRequirement>&, GlobalSignals) const EXCLUDES(mLock); FpsRange getSupportedRefreshRateRange() const EXCLUDES(mLock) { std::lock_guard lock(mLock); Loading Loading @@ -403,13 +403,8 @@ private: const std::function<bool(const RefreshRate&)>& shouldAddRefreshRate, std::vector<const RefreshRate*>* outRefreshRates) REQUIRES(mLock); std::optional<RefreshRate> getCachedBestRefreshRate(const std::vector<LayerRequirement>&, GlobalSignals, GlobalSignals* outSignalsConsidered) const REQUIRES(mLock); RefreshRate getBestRefreshRateLocked(const std::vector<LayerRequirement>&, GlobalSignals, GlobalSignals* outSignalsConsidered) const REQUIRES(mLock); std::pair<RefreshRate, GlobalSignals> getBestRefreshRateLocked( const std::vector<LayerRequirement>&, GlobalSignals) const REQUIRES(mLock); // Returns the refresh rate with the highest score in the collection specified from begin // to end. If there are more than one with the same highest refresh rate, the first one is Loading Loading @@ -497,14 +492,11 @@ private: const Config mConfig; bool mSupportsFrameRateOverrideByContent; struct GetBestRefreshRateInvocation { std::vector<LayerRequirement> layerRequirements; GlobalSignals globalSignals; GlobalSignals outSignalsConsidered; RefreshRate resultingBestRefreshRate; struct GetBestRefreshRateCache { std::pair<std::vector<LayerRequirement>, GlobalSignals> arguments; std::pair<RefreshRate, GlobalSignals> result; }; mutable std::optional<GetBestRefreshRateInvocation> lastBestRefreshRateInvocation GUARDED_BY(mLock); mutable std::optional<GetBestRefreshRateCache> mGetBestRefreshRateCache GUARDED_BY(mLock); // Declare mIdleTimer last to ensure its thread joins before the mutex/callbacks are destroyed. std::mutex mIdleTimerCallbacksMutex; Loading
services/surfaceflinger/Scheduler/Scheduler.cpp +25 −23 Original line number Diff line number Diff line Loading @@ -537,18 +537,19 @@ void Scheduler::chooseRefreshRateForContent() { ATRACE_CALL(); const auto refreshRateConfigs = holdRefreshRateConfigs(); scheduler::LayerHistory::Summary summary = mLayerHistory.summarize(*refreshRateConfigs, systemTime()); scheduler::RefreshRateConfigs::GlobalSignals consideredSignals; DisplayModePtr newMode; GlobalSignals consideredSignals; bool frameRateChanged; bool frameRateOverridesChanged; const auto refreshRateConfigs = holdRefreshRateConfigs(); LayerHistory::Summary summary = mLayerHistory.summarize(*refreshRateConfigs, systemTime()); { std::lock_guard<std::mutex> lock(mPolicyLock); mPolicy.contentRequirements = summary; mPolicy.contentRequirements = std::move(summary); newMode = calculateRefreshRateModeId(&consideredSignals); std::tie(newMode, consideredSignals) = chooseDisplayMode(); frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps()); if (mPolicy.mode == newMode) { Loading Loading @@ -678,8 +679,7 @@ void Scheduler::dumpVsync(std::string& out) const { mVsyncSchedule->dump(out); } bool Scheduler::updateFrameRateOverrides( scheduler::RefreshRateConfigs::GlobalSignals consideredSignals, Fps displayRefreshRate) { bool Scheduler::updateFrameRateOverrides(GlobalSignals consideredSignals, Fps displayRefreshRate) { const auto refreshRateConfigs = holdRefreshRateConfigs(); if (!refreshRateConfigs->supportsFrameRateOverrideByContent()) { return false; Loading @@ -697,9 +697,11 @@ bool Scheduler::updateFrameRateOverrides( template <class T> bool Scheduler::handleTimerStateChanged(T* currentState, T newState) { DisplayModePtr newMode; GlobalSignals consideredSignals; bool refreshRateChanged = false; bool frameRateOverridesChanged; scheduler::RefreshRateConfigs::GlobalSignals consideredSignals; const auto refreshRateConfigs = holdRefreshRateConfigs(); { std::lock_guard<std::mutex> lock(mPolicyLock); Loading @@ -707,7 +709,7 @@ bool Scheduler::handleTimerStateChanged(T* currentState, T newState) { return false; } *currentState = newState; newMode = calculateRefreshRateModeId(&consideredSignals); std::tie(newMode, consideredSignals) = chooseDisplayMode(); frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps()); if (mPolicy.mode == newMode) { // We don't need to change the display mode, but we might need to send an event Loading @@ -733,33 +735,33 @@ bool Scheduler::handleTimerStateChanged(T* currentState, T newState) { return consideredSignals.touch; } DisplayModePtr Scheduler::calculateRefreshRateModeId( scheduler::RefreshRateConfigs::GlobalSignals* consideredSignals) { auto Scheduler::chooseDisplayMode() -> std::pair<DisplayModePtr, GlobalSignals> { ATRACE_CALL(); if (consideredSignals) *consideredSignals = {}; const auto refreshRateConfigs = holdRefreshRateConfigs(); const auto configs = holdRefreshRateConfigs(); // If Display Power is not in normal operation we want to be in performance mode. When coming // back to normal mode, a grace period is given with DisplayPowerTimer. if (mDisplayPowerTimer && (!mPolicy.isDisplayPowerStateNormal || mPolicy.displayPowerTimer == TimerState::Reset)) { return refreshRateConfigs->getMaxRefreshRateByPolicy().getMode(); constexpr GlobalSignals kNoSignals; return {configs->getMaxRefreshRateByPolicy().getMode(), kNoSignals}; } const bool touchActive = mTouchTimer && mPolicy.touch == TouchState::Active; const bool idle = mPolicy.idleTimer == TimerState::Expired; const GlobalSignals signals{.touch = mTouchTimer && mPolicy.touch == TouchState::Active, .idle = mPolicy.idleTimer == TimerState::Expired}; const auto [refreshRate, consideredSignals] = configs->getBestRefreshRate(mPolicy.contentRequirements, signals); return refreshRateConfigs ->getBestRefreshRate(mPolicy.contentRequirements, {.touch = touchActive, .idle = idle}, consideredSignals) .getMode(); return {refreshRate.getMode(), consideredSignals}; } DisplayModePtr Scheduler::getPreferredDisplayMode() { std::lock_guard<std::mutex> lock(mPolicyLock); // Make sure that the default mode ID is first updated, before returned. // Make sure the stored mode is up to date. if (mPolicy.mode) { mPolicy.mode = calculateRefreshRateModeId(); mPolicy.mode = chooseDisplayMode().first; } return mPolicy.mode; } Loading
services/surfaceflinger/Scheduler/Scheduler.h +6 −7 Original line number Diff line number Diff line Loading @@ -269,15 +269,14 @@ private: void setVsyncPeriod(nsecs_t period); // This function checks whether individual features that are affecting the refresh rate // selection were initialized, prioritizes them, and calculates the DisplayModeId // for the suggested refresh rate. DisplayModePtr calculateRefreshRateModeId( RefreshRateConfigs::GlobalSignals* consideredSignals = nullptr) REQUIRES(mPolicyLock); using GlobalSignals = RefreshRateConfigs::GlobalSignals; // Returns the display mode that fulfills the policy, and the signals that were considered. std::pair<DisplayModePtr, GlobalSignals> chooseDisplayMode() REQUIRES(mPolicyLock); bool updateFrameRateOverrides(GlobalSignals, Fps displayRefreshRate) REQUIRES(mPolicyLock); void dispatchCachedReportedMode() REQUIRES(mPolicyLock) EXCLUDES(mRefreshRateConfigsLock); bool updateFrameRateOverrides(RefreshRateConfigs::GlobalSignals, Fps displayRefreshRate) REQUIRES(mPolicyLock); impl::EventThread::ThrottleVsyncCallback makeThrottleVsyncCallback() const EXCLUDES(mRefreshRateConfigsLock); Loading
services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +260 −273 File changed.Preview size limit exceeded, changes collapsed. Show changes