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