Loading services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +130 −92 Original line number Diff line number Diff line Loading @@ -48,24 +48,6 @@ struct RefreshRateScore { } fixedRateBelowThresholdLayersScore; }; template <typename Iterator> const DisplayModePtr& getMaxScoreRefreshRate(Iterator begin, Iterator end) { const auto it = std::max_element(begin, end, [](RefreshRateScore max, RefreshRateScore current) { const auto& [modeIt, overallScore, _] = current; std::string name = to_string(modeIt->second->getFps()); ALOGV("%s scores %.2f", name.c_str(), overallScore); ATRACE_INT(name.c_str(), static_cast<int>(std::round(overallScore * 100))); constexpr float kEpsilon = 0.0001f; return overallScore > max.overallScore * (1 + kEpsilon); }); return it->modeIt->second; } constexpr RefreshRateConfigs::GlobalSignals kNoSignals; std::string formatLayerInfo(const RefreshRateConfigs::LayerRequirement& layer, float weight) { Loading Loading @@ -137,6 +119,34 @@ bool canModesSupportFrameRateOverride(const std::vector<DisplayModeIterator>& so } // namespace struct RefreshRateConfigs::RefreshRateScoreComparator { bool operator()(const RefreshRateScore& lhs, const RefreshRateScore& rhs) const { const auto& [modeIt, overallScore, _] = lhs; std::string name = to_string(modeIt->second->getFps()); ALOGV("%s sorting scores %.2f", name.c_str(), overallScore); ATRACE_INT(name.c_str(), static_cast<int>(std::round(overallScore * 100))); constexpr float kEpsilon = 0.0001f; if (std::abs(overallScore - rhs.overallScore) > kEpsilon) { return overallScore > rhs.overallScore; } // If overallScore tie we will pick the higher refresh rate if // high refresh rate is the priority else the lower refresh rate. if (refreshRateOrder == RefreshRateOrder::Descending) { using fps_approx_ops::operator>; return modeIt->second->getFps() > rhs.modeIt->second->getFps(); } else { using fps_approx_ops::operator<; return modeIt->second->getFps() < rhs.modeIt->second->getFps(); } } const RefreshRateOrder refreshRateOrder; }; std::string RefreshRateConfigs::Policy::toString() const { return base::StringPrintf("{defaultModeId=%d, allowGroupSwitching=%s" ", primaryRange=%s, appRequestRange=%s}", Loading Loading @@ -218,6 +228,13 @@ float RefreshRateConfigs::calculateNonExactMatchingLayerScoreLocked(const LayerR return 0; } float RefreshRateConfigs::calculateRefreshRateScoreForFps(Fps refreshRate) const { const float ratio = refreshRate.getValue() / mAppRequestRefreshRates.back()->second->getFps().getValue(); // Use ratio^2 to get a lower score the more we get further from peak return ratio * ratio; } float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& layer, Fps refreshRate, bool isSeamlessSwitch) const { // Slightly prefer seamless switches. Loading @@ -226,10 +243,7 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye // If the layer wants Max, give higher score to the higher refresh rate if (layer.vote == LayerVoteType::Max) { const auto& maxRefreshRate = mAppRequestRefreshRates.back()->second; const auto ratio = refreshRate.getValue() / maxRefreshRate->getFps().getValue(); // use ratio^2 to get a lower score the more we get further from peak return ratio * ratio; return calculateRefreshRateScoreForFps(refreshRate); } if (layer.vote == LayerVoteType::ExplicitExact) { Loading Loading @@ -258,24 +272,24 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye kNonExactMatchingPenalty; } auto RefreshRateConfigs::getBestRefreshRate(const std::vector<LayerRequirement>& layers, auto RefreshRateConfigs::getRankedRefreshRates(const std::vector<LayerRequirement>& layers, GlobalSignals signals) const -> std::pair<DisplayModePtr, GlobalSignals> { -> std::pair<std::vector<RefreshRateRanking>, GlobalSignals> { std::lock_guard lock(mLock); if (mGetBestRefreshRateCache && mGetBestRefreshRateCache->arguments == std::make_pair(layers, signals)) { return mGetBestRefreshRateCache->result; if (mGetRankedRefreshRatesCache && mGetRankedRefreshRatesCache->arguments == std::make_pair(layers, signals)) { return mGetRankedRefreshRatesCache->result; } const auto result = getBestRefreshRateLocked(layers, signals); mGetBestRefreshRateCache = GetBestRefreshRateCache{{layers, signals}, result}; const auto result = getRankedRefreshRatesLocked(layers, signals); mGetRankedRefreshRatesCache = GetRankedRefreshRatesCache{{layers, signals}, result}; return result; } auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequirement>& layers, auto RefreshRateConfigs::getRankedRefreshRatesLocked(const std::vector<LayerRequirement>& layers, GlobalSignals signals) const -> std::pair<DisplayModePtr, GlobalSignals> { -> std::pair<std::vector<RefreshRateRanking>, GlobalSignals> { using namespace fps_approx_ops; ATRACE_CALL(); ALOGV("%s: %zu layers", __func__, layers.size()); Loading @@ -285,8 +299,8 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire // Keep the display at max refresh rate for the duration of powering on the display. if (signals.powerOnImminent) { ALOGV("Power On Imminent"); const auto& max = getMaxRefreshRateByPolicyLocked(activeMode.getGroup()); return {max, GlobalSignals{.powerOnImminent = true}}; return {getRefreshRatesByPolicyLocked(activeMode.getGroup(), RefreshRateOrder::Descending), GlobalSignals{.powerOnImminent = true}}; } int noVoteLayers = 0; Loading @@ -295,7 +309,6 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire int explicitDefaultVoteLayers = 0; int explicitExactOrMultipleVoteLayers = 0; int explicitExact = 0; float maxExplicitWeight = 0; int seamedFocusedLayers = 0; for (const auto& layer : layers) { Loading @@ -311,15 +324,12 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire break; case LayerVoteType::ExplicitDefault: explicitDefaultVoteLayers++; maxExplicitWeight = std::max(maxExplicitWeight, layer.weight); break; case LayerVoteType::ExplicitExactOrMultiple: explicitExactOrMultipleVoteLayers++; maxExplicitWeight = std::max(maxExplicitWeight, layer.weight); break; case LayerVoteType::ExplicitExact: explicitExact++; maxExplicitWeight = std::max(maxExplicitWeight, layer.weight); break; case LayerVoteType::Heuristic: break; Loading Loading @@ -348,9 +358,9 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire // 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 (signals.touch && !hasExplicitVoteLayers) { const DisplayModePtr& max = getMaxRefreshRateByPolicyLocked(anchorGroup); ALOGV("TouchBoost - choose %s", to_string(max->getFps()).c_str()); return {max, GlobalSignals{.touch = true}}; ALOGV("Touch Boost"); return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending), GlobalSignals{.touch = true}}; } // If the primary range consists of a single refresh rate then we can only Loading @@ -360,22 +370,22 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire isApproxEqual(policy->primaryRange.min, policy->primaryRange.max); if (!signals.touch && signals.idle && !(primaryRangeIsSingleRate && hasExplicitVoteLayers)) { const DisplayModePtr& min = getMinRefreshRateByPolicyLocked(); ALOGV("Idle - choose %s", to_string(min->getFps()).c_str()); return {min, GlobalSignals{.idle = true}}; ALOGV("Idle"); return {getRefreshRatesByPolicyLocked(activeMode.getGroup(), RefreshRateOrder::Ascending), GlobalSignals{.idle = true}}; } if (layers.empty() || noVoteLayers == layers.size()) { const DisplayModePtr& max = getMaxRefreshRateByPolicyLocked(anchorGroup); ALOGV("no layers with votes - choose %s", to_string(max->getFps()).c_str()); return {max, kNoSignals}; ALOGV("No layers with votes"); return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending), kNoSignals}; } // Only if all layers want Min we should return Min if (noVoteLayers + minVoteLayers == layers.size()) { const DisplayModePtr& min = getMinRefreshRateByPolicyLocked(); ALOGV("all layers Min - choose %s", to_string(min->getFps()).c_str()); return {min, kNoSignals}; ALOGV("All layers Min"); return {getRefreshRatesByPolicyLocked(activeMode.getGroup(), RefreshRateOrder::Ascending), kNoSignals}; } // Find the best refresh rate based on score Loading Loading @@ -522,22 +532,29 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire } // Now that we scored all the refresh rates we need to pick the one that got the highest // overallScore. In case of a tie we will pick the higher refresh rate if any of the layers // wanted Max, or the lower otherwise. const DisplayModePtr& bestRefreshRate = maxVoteLayers > 0 ? getMaxScoreRefreshRate(scores.rbegin(), scores.rend()) : getMaxScoreRefreshRate(scores.begin(), scores.end()); // overallScore. Sort the scores based on their overallScore in descending order of priority. const RefreshRateOrder refreshRateOrder = maxVoteLayers > 0 ? RefreshRateOrder::Descending : RefreshRateOrder::Ascending; std::sort(scores.begin(), scores.end(), RefreshRateScoreComparator{.refreshRateOrder = refreshRateOrder}); std::vector<RefreshRateRanking> rankedRefreshRates; rankedRefreshRates.reserve(scores.size()); std::transform(scores.begin(), scores.end(), back_inserter(rankedRefreshRates), [](const RefreshRateScore& score) { return RefreshRateRanking{score.modeIt->second, score.overallScore}; }); if (primaryRangeIsSingleRate) { // If we never scored any layers, then choose the rate from the primary // range instead of picking a random score from the app range. if (std::all_of(scores.begin(), scores.end(), [](RefreshRateScore score) { return score.overallScore == 0; })) { const DisplayModePtr& max = getMaxRefreshRateByPolicyLocked(anchorGroup); ALOGV("layers not scored - choose %s", to_string(max->getFps()).c_str()); return {max, kNoSignals}; ALOGV("Layers not scored"); return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending), kNoSignals}; } else { return {bestRefreshRate, kNoSignals}; return {rankedRefreshRates, kNoSignals}; } } Loading @@ -545,8 +562,6 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire // interactive (as opposed to ExplicitExactOrMultiple) and therefore if those posted an explicit // vote we should not change it if we get a touch event. Only apply touch boost if it will // actually increase the refresh rate over the normal selection. const DisplayModePtr& touchRefreshRate = getMaxRefreshRateByPolicyLocked(anchorGroup); const bool touchBoostForExplicitExact = [&] { if (mSupportsFrameRateOverrideByContent) { // Enable touch boost if there are other layers besides exact Loading @@ -557,15 +572,18 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire } }(); const auto& touchRefreshRates = getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending); using fps_approx_ops::operator<; if (signals.touch && explicitDefaultVoteLayers == 0 && touchBoostForExplicitExact && bestRefreshRate->getFps() < touchRefreshRate->getFps()) { ALOGV("TouchBoost - choose %s", to_string(touchRefreshRate->getFps()).c_str()); return {touchRefreshRate, GlobalSignals{.touch = true}}; scores.front().modeIt->second->getFps() < touchRefreshRates.front().displayModePtr->getFps()) { ALOGV("Touch Boost"); return {touchRefreshRates, GlobalSignals{.touch = true}}; } return {bestRefreshRate, kNoSignals}; return {rankedRefreshRates, kNoSignals}; } std::unordered_map<uid_t, std::vector<const RefreshRateConfigs::LayerRequirement*>> Loading Loading @@ -670,11 +688,13 @@ RefreshRateConfigs::UidToFrameRateOverride RefreshRateConfigs::getFrameRateOverr continue; } // Now that we scored all the refresh rates we need to pick the one that got the highest // score. // Now that we scored all the refresh rates we need to pick the lowest refresh rate // that got the highest score. const DisplayModePtr& bestRefreshRate = getMaxScoreRefreshRate(scores.begin(), scores.end()); std::min_element(scores.begin(), scores.end(), RefreshRateScoreComparator{.refreshRateOrder = RefreshRateOrder::Ascending}) ->modeIt->second; frameRateOverrides.emplace(uid, bestRefreshRate->getFps()); } Loading Loading @@ -715,16 +735,6 @@ const DisplayModePtr& RefreshRateConfigs::getMinRefreshRateByPolicyLocked() cons return mPrimaryRefreshRates.front()->second; } DisplayModePtr RefreshRateConfigs::getMaxRefreshRateByPolicy() const { std::lock_guard lock(mLock); return getMaxRefreshRateByPolicyLocked(); } const DisplayModePtr& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked() const { const int anchorGroup = getActiveModeItLocked()->second->getGroup(); return getMaxRefreshRateByPolicyLocked(anchorGroup); } const DisplayModePtr& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked(int anchorGroup) const { for (auto it = mPrimaryRefreshRates.rbegin(); it != mPrimaryRefreshRates.rend(); ++it) { const auto& mode = (*it)->second; Loading @@ -733,14 +743,41 @@ const DisplayModePtr& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked(int an } } const auto& activeMode = *getActiveModeItLocked()->second; ALOGE("Can't find max refresh rate by policy with the same mode group as the current mode %s", to_string(activeMode).c_str()); ALOGE("Can't find max refresh rate by policy with the same group %d", anchorGroup); // Default to the highest refresh rate. return mPrimaryRefreshRates.back()->second; } std::vector<RefreshRateRanking> RefreshRateConfigs::getRefreshRatesByPolicyLocked( std::optional<int> anchorGroupOpt, RefreshRateOrder refreshRateOrder) const { std::vector<RefreshRateRanking> rankings; const auto makeRanking = [&](const DisplayModeIterator it) REQUIRES(mLock) { const auto& mode = it->second; const bool inverseScore = (refreshRateOrder == RefreshRateOrder::Ascending); const float score = calculateRefreshRateScoreForFps(mode->getFps()); if (!anchorGroupOpt || mode->getGroup() == anchorGroupOpt) { rankings.push_back(RefreshRateRanking{mode, inverseScore ? 1.0f / score : score}); } }; if (refreshRateOrder == RefreshRateOrder::Ascending) { std::for_each(mPrimaryRefreshRates.begin(), mPrimaryRefreshRates.end(), makeRanking); } else { std::for_each(mPrimaryRefreshRates.rbegin(), mPrimaryRefreshRates.rend(), makeRanking); } if (!rankings.empty() || !anchorGroupOpt) { return rankings; } ALOGW("Can't find %s refresh rate by policy with the same mode group" " as the mode group %d", refreshRateOrder == RefreshRateOrder::Ascending ? "min" : "max", anchorGroupOpt.value()); return getRefreshRatesByPolicyLocked(/*anchorGroupOpt*/ std::nullopt, refreshRateOrder); } DisplayModePtr RefreshRateConfigs::getActiveModePtr() const { std::lock_guard lock(mLock); return getActiveModeItLocked()->second; Loading @@ -760,9 +797,9 @@ DisplayModeIterator RefreshRateConfigs::getActiveModeItLocked() const { void RefreshRateConfigs::setActiveModeId(DisplayModeId modeId) { std::lock_guard lock(mLock); // Invalidate the cached invocation to getBestRefreshRate. This forces // the refresh rate to be recomputed on the next call to getBestRefreshRate. mGetBestRefreshRateCache.reset(); // Invalidate the cached invocation to getRankedRefreshRates. This forces // the refresh rate to be recomputed on the next call to getRankedRefreshRates. mGetRankedRefreshRatesCache.reset(); mActiveModeIt = mDisplayModes.find(modeId); LOG_ALWAYS_FATAL_IF(mActiveModeIt == mDisplayModes.end()); Loading Loading @@ -797,9 +834,9 @@ void RefreshRateConfigs::initializeIdleTimer() { void RefreshRateConfigs::updateDisplayModes(DisplayModes modes, DisplayModeId activeModeId) { std::lock_guard lock(mLock); // Invalidate the cached invocation to getBestRefreshRate. This forces // the refresh rate to be recomputed on the next call to getBestRefreshRate. mGetBestRefreshRateCache.reset(); // Invalidate the cached invocation to getRankedRefreshRates. This forces // the refresh rate to be recomputed on the next call to getRankedRefreshRates. mGetRankedRefreshRatesCache.reset(); mDisplayModes = std::move(modes); mActiveModeIt = mDisplayModes.find(activeModeId); Loading Loading @@ -843,7 +880,7 @@ status_t RefreshRateConfigs::setDisplayManagerPolicy(const Policy& policy) { ALOGE("Invalid refresh rate policy: %s", policy.toString().c_str()); return BAD_VALUE; } mGetBestRefreshRateCache.reset(); mGetRankedRefreshRatesCache.reset(); Policy previousPolicy = *getCurrentPolicyLocked(); mDisplayManagerPolicy = policy; if (*getCurrentPolicyLocked() == previousPolicy) { Loading @@ -858,7 +895,7 @@ status_t RefreshRateConfigs::setOverridePolicy(const std::optional<Policy>& poli if (policy && !isPolicyValidLocked(*policy)) { return BAD_VALUE; } mGetBestRefreshRateCache.reset(); mGetRankedRefreshRatesCache.reset(); Policy previousPolicy = *getCurrentPolicyLocked(); mOverridePolicy = policy; if (*getCurrentPolicyLocked() == previousPolicy) { Loading Loading @@ -958,7 +995,8 @@ RefreshRateConfigs::KernelIdleTimerAction RefreshRateConfigs::getIdleTimerAction return KernelIdleTimerAction::TurnOff; } const DisplayModePtr& maxByPolicy = getMaxRefreshRateByPolicyLocked(); const DisplayModePtr& maxByPolicy = getMaxRefreshRateByPolicyLocked(getActiveModeItLocked()->second->getGroup()); if (minByPolicy == maxByPolicy) { // Turn on the timer when the min of the primary range is below the device min. if (const Policy* currentPolicy = getCurrentPolicyLocked(); Loading services/surfaceflinger/Scheduler/RefreshRateConfigs.h +28 −12 Original line number Diff line number Diff line Loading @@ -44,6 +44,15 @@ inline DisplayModeEvent operator|(DisplayModeEvent lhs, DisplayModeEvent rhs) { return static_cast<DisplayModeEvent>(static_cast<T>(lhs) | static_cast<T>(rhs)); } struct RefreshRateRanking { DisplayModePtr displayModePtr; float score = 0.0f; bool operator==(const RefreshRateRanking& ranking) const { return displayModePtr == ranking.displayModePtr && score == ranking.score; } }; using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride; /** Loading Loading @@ -195,9 +204,9 @@ public: } }; // 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<DisplayModePtr, GlobalSignals> getBestRefreshRate( // Returns the list in the descending order of refresh rates desired // based on their overall score, and the GlobalSignals that were considered. std::pair<std::vector<RefreshRateRanking>, GlobalSignals> getRankedRefreshRates( const std::vector<LayerRequirement>&, GlobalSignals) const EXCLUDES(mLock); FpsRange getSupportedRefreshRateRange() const EXCLUDES(mLock) { Loading @@ -208,10 +217,6 @@ public: std::optional<Fps> onKernelTimerChanged(std::optional<DisplayModeId> desiredActiveModeId, bool timerExpired) const EXCLUDES(mLock); // Returns the highest refresh rate according to the current policy. May change at runtime. Only // uses the primary range, not the app request range. DisplayModePtr getMaxRefreshRateByPolicy() const EXCLUDES(mLock); void setActiveModeId(DisplayModeId) EXCLUDES(mLock) REQUIRES(kMainThreadContext); // See mActiveModeIt for thread safety. Loading Loading @@ -343,7 +348,7 @@ private: // See mActiveModeIt for thread safety. DisplayModeIterator getActiveModeItLocked() const REQUIRES(mLock); std::pair<DisplayModePtr, GlobalSignals> getBestRefreshRateLocked( std::pair<std::vector<RefreshRateRanking>, GlobalSignals> getRankedRefreshRatesLocked( const std::vector<LayerRequirement>&, GlobalSignals) const REQUIRES(mLock); // Returns number of display frames and remainder when dividing the layer refresh period by Loading @@ -356,12 +361,23 @@ private: // Returns the highest refresh rate according to the current policy. May change at runtime. Only // uses the primary range, not the app request range. const DisplayModePtr& getMaxRefreshRateByPolicyLocked() const REQUIRES(mLock); const DisplayModePtr& getMaxRefreshRateByPolicyLocked(int anchorGroup) const REQUIRES(mLock); struct RefreshRateScoreComparator; enum class RefreshRateOrder { Ascending, Descending }; // Returns the rankings in RefreshRateOrder. May change at runtime. // Only uses the primary range, not the app request range. std::vector<RefreshRateRanking> getRefreshRatesByPolicyLocked(std::optional<int> anchorGroupOpt, RefreshRateOrder) const REQUIRES(mLock); const Policy* getCurrentPolicyLocked() const REQUIRES(mLock); bool isPolicyValidLocked(const Policy& policy) const REQUIRES(mLock); // Returns the refresh rate score as a ratio to max refresh rate, which has a score of 1. float calculateRefreshRateScoreForFps(Fps refreshRate) const REQUIRES(mLock); // calculates a score for a layer. Used to determine the display refresh rate // and the frame rate override for certains applications. float calculateLayerScoreLocked(const LayerRequirement&, Fps refreshRate, Loading Loading @@ -410,11 +426,11 @@ private: const Config mConfig; bool mSupportsFrameRateOverrideByContent; struct GetBestRefreshRateCache { struct GetRankedRefreshRatesCache { std::pair<std::vector<LayerRequirement>, GlobalSignals> arguments; std::pair<DisplayModePtr, GlobalSignals> result; std::pair<std::vector<RefreshRateRanking>, GlobalSignals> result; }; mutable std::optional<GetBestRefreshRateCache> mGetBestRefreshRateCache GUARDED_BY(mLock); mutable std::optional<GetRankedRefreshRatesCache> mGetRankedRefreshRatesCache 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 +7 −4 Original line number Diff line number Diff line Loading @@ -674,7 +674,9 @@ auto Scheduler::applyPolicy(S Policy::*statePtr, T&& newState) -> GlobalSignals if (currentState == newState) return {}; currentState = std::forward<T>(newState); std::tie(newMode, consideredSignals) = chooseDisplayMode(); const auto [rankings, signals] = getRankedDisplayModes(); newMode = rankings.front().displayModePtr; consideredSignals = signals; frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps()); if (mPolicy.mode == newMode) { Loading @@ -699,7 +701,8 @@ auto Scheduler::applyPolicy(S Policy::*statePtr, T&& newState) -> GlobalSignals return consideredSignals; } auto Scheduler::chooseDisplayMode() -> std::pair<DisplayModePtr, GlobalSignals> { auto Scheduler::getRankedDisplayModes() -> std::pair<std::vector<RefreshRateRanking>, GlobalSignals> { ATRACE_CALL(); const auto configs = holdRefreshRateConfigs(); Loading @@ -712,14 +715,14 @@ auto Scheduler::chooseDisplayMode() -> std::pair<DisplayModePtr, GlobalSignals> .idle = mPolicy.idleTimer == TimerState::Expired, .powerOnImminent = powerOnImminent}; return configs->getBestRefreshRate(mPolicy.contentRequirements, signals); return configs->getRankedRefreshRates(mPolicy.contentRequirements, signals); } DisplayModePtr Scheduler::getPreferredDisplayMode() { std::lock_guard<std::mutex> lock(mPolicyLock); // Make sure the stored mode is up to date. if (mPolicy.mode) { mPolicy.mode = chooseDisplayMode().first; mPolicy.mode = getRankedDisplayModes().first.front().displayModePtr; } return mPolicy.mode; } Loading services/surfaceflinger/Scheduler/Scheduler.h +4 −2 Original line number Diff line number Diff line Loading @@ -269,8 +269,10 @@ private: template <typename S, typename T> GlobalSignals applyPolicy(S Policy::*, T&&) EXCLUDES(mPolicyLock); // Returns the display mode that fulfills the policy, and the signals that were considered. std::pair<DisplayModePtr, GlobalSignals> chooseDisplayMode() REQUIRES(mPolicyLock); // Returns the list of display modes in descending order of their priority that fulfills the // policy, and the signals that were considered. std::pair<std::vector<RefreshRateRanking>, GlobalSignals> getRankedDisplayModes() REQUIRES(mPolicyLock); bool updateFrameRateOverrides(GlobalSignals, Fps displayRefreshRate) REQUIRES(mPolicyLock); Loading services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -350,7 +350,7 @@ void SchedulerFuzzer::fuzzRefreshRateConfigs() { const RefreshRateConfigs::GlobalSignals globalSignals = {.touch = false, .idle = false}; std::vector<LayerRequirement> layers = {{.weight = mFdp.ConsumeFloatingPoint<float>()}}; refreshRateConfigs.getBestRefreshRate(layers, globalSignals); refreshRateConfigs.getRankedRefreshRates(layers, globalSignals); layers[0].name = mFdp.ConsumeRandomLengthString(kRandomStringLength); layers[0].ownerUid = mFdp.ConsumeIntegral<uint16_t>(); Loading Loading
services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +130 −92 Original line number Diff line number Diff line Loading @@ -48,24 +48,6 @@ struct RefreshRateScore { } fixedRateBelowThresholdLayersScore; }; template <typename Iterator> const DisplayModePtr& getMaxScoreRefreshRate(Iterator begin, Iterator end) { const auto it = std::max_element(begin, end, [](RefreshRateScore max, RefreshRateScore current) { const auto& [modeIt, overallScore, _] = current; std::string name = to_string(modeIt->second->getFps()); ALOGV("%s scores %.2f", name.c_str(), overallScore); ATRACE_INT(name.c_str(), static_cast<int>(std::round(overallScore * 100))); constexpr float kEpsilon = 0.0001f; return overallScore > max.overallScore * (1 + kEpsilon); }); return it->modeIt->second; } constexpr RefreshRateConfigs::GlobalSignals kNoSignals; std::string formatLayerInfo(const RefreshRateConfigs::LayerRequirement& layer, float weight) { Loading Loading @@ -137,6 +119,34 @@ bool canModesSupportFrameRateOverride(const std::vector<DisplayModeIterator>& so } // namespace struct RefreshRateConfigs::RefreshRateScoreComparator { bool operator()(const RefreshRateScore& lhs, const RefreshRateScore& rhs) const { const auto& [modeIt, overallScore, _] = lhs; std::string name = to_string(modeIt->second->getFps()); ALOGV("%s sorting scores %.2f", name.c_str(), overallScore); ATRACE_INT(name.c_str(), static_cast<int>(std::round(overallScore * 100))); constexpr float kEpsilon = 0.0001f; if (std::abs(overallScore - rhs.overallScore) > kEpsilon) { return overallScore > rhs.overallScore; } // If overallScore tie we will pick the higher refresh rate if // high refresh rate is the priority else the lower refresh rate. if (refreshRateOrder == RefreshRateOrder::Descending) { using fps_approx_ops::operator>; return modeIt->second->getFps() > rhs.modeIt->second->getFps(); } else { using fps_approx_ops::operator<; return modeIt->second->getFps() < rhs.modeIt->second->getFps(); } } const RefreshRateOrder refreshRateOrder; }; std::string RefreshRateConfigs::Policy::toString() const { return base::StringPrintf("{defaultModeId=%d, allowGroupSwitching=%s" ", primaryRange=%s, appRequestRange=%s}", Loading Loading @@ -218,6 +228,13 @@ float RefreshRateConfigs::calculateNonExactMatchingLayerScoreLocked(const LayerR return 0; } float RefreshRateConfigs::calculateRefreshRateScoreForFps(Fps refreshRate) const { const float ratio = refreshRate.getValue() / mAppRequestRefreshRates.back()->second->getFps().getValue(); // Use ratio^2 to get a lower score the more we get further from peak return ratio * ratio; } float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& layer, Fps refreshRate, bool isSeamlessSwitch) const { // Slightly prefer seamless switches. Loading @@ -226,10 +243,7 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye // If the layer wants Max, give higher score to the higher refresh rate if (layer.vote == LayerVoteType::Max) { const auto& maxRefreshRate = mAppRequestRefreshRates.back()->second; const auto ratio = refreshRate.getValue() / maxRefreshRate->getFps().getValue(); // use ratio^2 to get a lower score the more we get further from peak return ratio * ratio; return calculateRefreshRateScoreForFps(refreshRate); } if (layer.vote == LayerVoteType::ExplicitExact) { Loading Loading @@ -258,24 +272,24 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye kNonExactMatchingPenalty; } auto RefreshRateConfigs::getBestRefreshRate(const std::vector<LayerRequirement>& layers, auto RefreshRateConfigs::getRankedRefreshRates(const std::vector<LayerRequirement>& layers, GlobalSignals signals) const -> std::pair<DisplayModePtr, GlobalSignals> { -> std::pair<std::vector<RefreshRateRanking>, GlobalSignals> { std::lock_guard lock(mLock); if (mGetBestRefreshRateCache && mGetBestRefreshRateCache->arguments == std::make_pair(layers, signals)) { return mGetBestRefreshRateCache->result; if (mGetRankedRefreshRatesCache && mGetRankedRefreshRatesCache->arguments == std::make_pair(layers, signals)) { return mGetRankedRefreshRatesCache->result; } const auto result = getBestRefreshRateLocked(layers, signals); mGetBestRefreshRateCache = GetBestRefreshRateCache{{layers, signals}, result}; const auto result = getRankedRefreshRatesLocked(layers, signals); mGetRankedRefreshRatesCache = GetRankedRefreshRatesCache{{layers, signals}, result}; return result; } auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequirement>& layers, auto RefreshRateConfigs::getRankedRefreshRatesLocked(const std::vector<LayerRequirement>& layers, GlobalSignals signals) const -> std::pair<DisplayModePtr, GlobalSignals> { -> std::pair<std::vector<RefreshRateRanking>, GlobalSignals> { using namespace fps_approx_ops; ATRACE_CALL(); ALOGV("%s: %zu layers", __func__, layers.size()); Loading @@ -285,8 +299,8 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire // Keep the display at max refresh rate for the duration of powering on the display. if (signals.powerOnImminent) { ALOGV("Power On Imminent"); const auto& max = getMaxRefreshRateByPolicyLocked(activeMode.getGroup()); return {max, GlobalSignals{.powerOnImminent = true}}; return {getRefreshRatesByPolicyLocked(activeMode.getGroup(), RefreshRateOrder::Descending), GlobalSignals{.powerOnImminent = true}}; } int noVoteLayers = 0; Loading @@ -295,7 +309,6 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire int explicitDefaultVoteLayers = 0; int explicitExactOrMultipleVoteLayers = 0; int explicitExact = 0; float maxExplicitWeight = 0; int seamedFocusedLayers = 0; for (const auto& layer : layers) { Loading @@ -311,15 +324,12 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire break; case LayerVoteType::ExplicitDefault: explicitDefaultVoteLayers++; maxExplicitWeight = std::max(maxExplicitWeight, layer.weight); break; case LayerVoteType::ExplicitExactOrMultiple: explicitExactOrMultipleVoteLayers++; maxExplicitWeight = std::max(maxExplicitWeight, layer.weight); break; case LayerVoteType::ExplicitExact: explicitExact++; maxExplicitWeight = std::max(maxExplicitWeight, layer.weight); break; case LayerVoteType::Heuristic: break; Loading Loading @@ -348,9 +358,9 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire // 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 (signals.touch && !hasExplicitVoteLayers) { const DisplayModePtr& max = getMaxRefreshRateByPolicyLocked(anchorGroup); ALOGV("TouchBoost - choose %s", to_string(max->getFps()).c_str()); return {max, GlobalSignals{.touch = true}}; ALOGV("Touch Boost"); return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending), GlobalSignals{.touch = true}}; } // If the primary range consists of a single refresh rate then we can only Loading @@ -360,22 +370,22 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire isApproxEqual(policy->primaryRange.min, policy->primaryRange.max); if (!signals.touch && signals.idle && !(primaryRangeIsSingleRate && hasExplicitVoteLayers)) { const DisplayModePtr& min = getMinRefreshRateByPolicyLocked(); ALOGV("Idle - choose %s", to_string(min->getFps()).c_str()); return {min, GlobalSignals{.idle = true}}; ALOGV("Idle"); return {getRefreshRatesByPolicyLocked(activeMode.getGroup(), RefreshRateOrder::Ascending), GlobalSignals{.idle = true}}; } if (layers.empty() || noVoteLayers == layers.size()) { const DisplayModePtr& max = getMaxRefreshRateByPolicyLocked(anchorGroup); ALOGV("no layers with votes - choose %s", to_string(max->getFps()).c_str()); return {max, kNoSignals}; ALOGV("No layers with votes"); return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending), kNoSignals}; } // Only if all layers want Min we should return Min if (noVoteLayers + minVoteLayers == layers.size()) { const DisplayModePtr& min = getMinRefreshRateByPolicyLocked(); ALOGV("all layers Min - choose %s", to_string(min->getFps()).c_str()); return {min, kNoSignals}; ALOGV("All layers Min"); return {getRefreshRatesByPolicyLocked(activeMode.getGroup(), RefreshRateOrder::Ascending), kNoSignals}; } // Find the best refresh rate based on score Loading Loading @@ -522,22 +532,29 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire } // Now that we scored all the refresh rates we need to pick the one that got the highest // overallScore. In case of a tie we will pick the higher refresh rate if any of the layers // wanted Max, or the lower otherwise. const DisplayModePtr& bestRefreshRate = maxVoteLayers > 0 ? getMaxScoreRefreshRate(scores.rbegin(), scores.rend()) : getMaxScoreRefreshRate(scores.begin(), scores.end()); // overallScore. Sort the scores based on their overallScore in descending order of priority. const RefreshRateOrder refreshRateOrder = maxVoteLayers > 0 ? RefreshRateOrder::Descending : RefreshRateOrder::Ascending; std::sort(scores.begin(), scores.end(), RefreshRateScoreComparator{.refreshRateOrder = refreshRateOrder}); std::vector<RefreshRateRanking> rankedRefreshRates; rankedRefreshRates.reserve(scores.size()); std::transform(scores.begin(), scores.end(), back_inserter(rankedRefreshRates), [](const RefreshRateScore& score) { return RefreshRateRanking{score.modeIt->second, score.overallScore}; }); if (primaryRangeIsSingleRate) { // If we never scored any layers, then choose the rate from the primary // range instead of picking a random score from the app range. if (std::all_of(scores.begin(), scores.end(), [](RefreshRateScore score) { return score.overallScore == 0; })) { const DisplayModePtr& max = getMaxRefreshRateByPolicyLocked(anchorGroup); ALOGV("layers not scored - choose %s", to_string(max->getFps()).c_str()); return {max, kNoSignals}; ALOGV("Layers not scored"); return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending), kNoSignals}; } else { return {bestRefreshRate, kNoSignals}; return {rankedRefreshRates, kNoSignals}; } } Loading @@ -545,8 +562,6 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire // interactive (as opposed to ExplicitExactOrMultiple) and therefore if those posted an explicit // vote we should not change it if we get a touch event. Only apply touch boost if it will // actually increase the refresh rate over the normal selection. const DisplayModePtr& touchRefreshRate = getMaxRefreshRateByPolicyLocked(anchorGroup); const bool touchBoostForExplicitExact = [&] { if (mSupportsFrameRateOverrideByContent) { // Enable touch boost if there are other layers besides exact Loading @@ -557,15 +572,18 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire } }(); const auto& touchRefreshRates = getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending); using fps_approx_ops::operator<; if (signals.touch && explicitDefaultVoteLayers == 0 && touchBoostForExplicitExact && bestRefreshRate->getFps() < touchRefreshRate->getFps()) { ALOGV("TouchBoost - choose %s", to_string(touchRefreshRate->getFps()).c_str()); return {touchRefreshRate, GlobalSignals{.touch = true}}; scores.front().modeIt->second->getFps() < touchRefreshRates.front().displayModePtr->getFps()) { ALOGV("Touch Boost"); return {touchRefreshRates, GlobalSignals{.touch = true}}; } return {bestRefreshRate, kNoSignals}; return {rankedRefreshRates, kNoSignals}; } std::unordered_map<uid_t, std::vector<const RefreshRateConfigs::LayerRequirement*>> Loading Loading @@ -670,11 +688,13 @@ RefreshRateConfigs::UidToFrameRateOverride RefreshRateConfigs::getFrameRateOverr continue; } // Now that we scored all the refresh rates we need to pick the one that got the highest // score. // Now that we scored all the refresh rates we need to pick the lowest refresh rate // that got the highest score. const DisplayModePtr& bestRefreshRate = getMaxScoreRefreshRate(scores.begin(), scores.end()); std::min_element(scores.begin(), scores.end(), RefreshRateScoreComparator{.refreshRateOrder = RefreshRateOrder::Ascending}) ->modeIt->second; frameRateOverrides.emplace(uid, bestRefreshRate->getFps()); } Loading Loading @@ -715,16 +735,6 @@ const DisplayModePtr& RefreshRateConfigs::getMinRefreshRateByPolicyLocked() cons return mPrimaryRefreshRates.front()->second; } DisplayModePtr RefreshRateConfigs::getMaxRefreshRateByPolicy() const { std::lock_guard lock(mLock); return getMaxRefreshRateByPolicyLocked(); } const DisplayModePtr& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked() const { const int anchorGroup = getActiveModeItLocked()->second->getGroup(); return getMaxRefreshRateByPolicyLocked(anchorGroup); } const DisplayModePtr& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked(int anchorGroup) const { for (auto it = mPrimaryRefreshRates.rbegin(); it != mPrimaryRefreshRates.rend(); ++it) { const auto& mode = (*it)->second; Loading @@ -733,14 +743,41 @@ const DisplayModePtr& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked(int an } } const auto& activeMode = *getActiveModeItLocked()->second; ALOGE("Can't find max refresh rate by policy with the same mode group as the current mode %s", to_string(activeMode).c_str()); ALOGE("Can't find max refresh rate by policy with the same group %d", anchorGroup); // Default to the highest refresh rate. return mPrimaryRefreshRates.back()->second; } std::vector<RefreshRateRanking> RefreshRateConfigs::getRefreshRatesByPolicyLocked( std::optional<int> anchorGroupOpt, RefreshRateOrder refreshRateOrder) const { std::vector<RefreshRateRanking> rankings; const auto makeRanking = [&](const DisplayModeIterator it) REQUIRES(mLock) { const auto& mode = it->second; const bool inverseScore = (refreshRateOrder == RefreshRateOrder::Ascending); const float score = calculateRefreshRateScoreForFps(mode->getFps()); if (!anchorGroupOpt || mode->getGroup() == anchorGroupOpt) { rankings.push_back(RefreshRateRanking{mode, inverseScore ? 1.0f / score : score}); } }; if (refreshRateOrder == RefreshRateOrder::Ascending) { std::for_each(mPrimaryRefreshRates.begin(), mPrimaryRefreshRates.end(), makeRanking); } else { std::for_each(mPrimaryRefreshRates.rbegin(), mPrimaryRefreshRates.rend(), makeRanking); } if (!rankings.empty() || !anchorGroupOpt) { return rankings; } ALOGW("Can't find %s refresh rate by policy with the same mode group" " as the mode group %d", refreshRateOrder == RefreshRateOrder::Ascending ? "min" : "max", anchorGroupOpt.value()); return getRefreshRatesByPolicyLocked(/*anchorGroupOpt*/ std::nullopt, refreshRateOrder); } DisplayModePtr RefreshRateConfigs::getActiveModePtr() const { std::lock_guard lock(mLock); return getActiveModeItLocked()->second; Loading @@ -760,9 +797,9 @@ DisplayModeIterator RefreshRateConfigs::getActiveModeItLocked() const { void RefreshRateConfigs::setActiveModeId(DisplayModeId modeId) { std::lock_guard lock(mLock); // Invalidate the cached invocation to getBestRefreshRate. This forces // the refresh rate to be recomputed on the next call to getBestRefreshRate. mGetBestRefreshRateCache.reset(); // Invalidate the cached invocation to getRankedRefreshRates. This forces // the refresh rate to be recomputed on the next call to getRankedRefreshRates. mGetRankedRefreshRatesCache.reset(); mActiveModeIt = mDisplayModes.find(modeId); LOG_ALWAYS_FATAL_IF(mActiveModeIt == mDisplayModes.end()); Loading Loading @@ -797,9 +834,9 @@ void RefreshRateConfigs::initializeIdleTimer() { void RefreshRateConfigs::updateDisplayModes(DisplayModes modes, DisplayModeId activeModeId) { std::lock_guard lock(mLock); // Invalidate the cached invocation to getBestRefreshRate. This forces // the refresh rate to be recomputed on the next call to getBestRefreshRate. mGetBestRefreshRateCache.reset(); // Invalidate the cached invocation to getRankedRefreshRates. This forces // the refresh rate to be recomputed on the next call to getRankedRefreshRates. mGetRankedRefreshRatesCache.reset(); mDisplayModes = std::move(modes); mActiveModeIt = mDisplayModes.find(activeModeId); Loading Loading @@ -843,7 +880,7 @@ status_t RefreshRateConfigs::setDisplayManagerPolicy(const Policy& policy) { ALOGE("Invalid refresh rate policy: %s", policy.toString().c_str()); return BAD_VALUE; } mGetBestRefreshRateCache.reset(); mGetRankedRefreshRatesCache.reset(); Policy previousPolicy = *getCurrentPolicyLocked(); mDisplayManagerPolicy = policy; if (*getCurrentPolicyLocked() == previousPolicy) { Loading @@ -858,7 +895,7 @@ status_t RefreshRateConfigs::setOverridePolicy(const std::optional<Policy>& poli if (policy && !isPolicyValidLocked(*policy)) { return BAD_VALUE; } mGetBestRefreshRateCache.reset(); mGetRankedRefreshRatesCache.reset(); Policy previousPolicy = *getCurrentPolicyLocked(); mOverridePolicy = policy; if (*getCurrentPolicyLocked() == previousPolicy) { Loading Loading @@ -958,7 +995,8 @@ RefreshRateConfigs::KernelIdleTimerAction RefreshRateConfigs::getIdleTimerAction return KernelIdleTimerAction::TurnOff; } const DisplayModePtr& maxByPolicy = getMaxRefreshRateByPolicyLocked(); const DisplayModePtr& maxByPolicy = getMaxRefreshRateByPolicyLocked(getActiveModeItLocked()->second->getGroup()); if (minByPolicy == maxByPolicy) { // Turn on the timer when the min of the primary range is below the device min. if (const Policy* currentPolicy = getCurrentPolicyLocked(); Loading
services/surfaceflinger/Scheduler/RefreshRateConfigs.h +28 −12 Original line number Diff line number Diff line Loading @@ -44,6 +44,15 @@ inline DisplayModeEvent operator|(DisplayModeEvent lhs, DisplayModeEvent rhs) { return static_cast<DisplayModeEvent>(static_cast<T>(lhs) | static_cast<T>(rhs)); } struct RefreshRateRanking { DisplayModePtr displayModePtr; float score = 0.0f; bool operator==(const RefreshRateRanking& ranking) const { return displayModePtr == ranking.displayModePtr && score == ranking.score; } }; using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride; /** Loading Loading @@ -195,9 +204,9 @@ public: } }; // 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<DisplayModePtr, GlobalSignals> getBestRefreshRate( // Returns the list in the descending order of refresh rates desired // based on their overall score, and the GlobalSignals that were considered. std::pair<std::vector<RefreshRateRanking>, GlobalSignals> getRankedRefreshRates( const std::vector<LayerRequirement>&, GlobalSignals) const EXCLUDES(mLock); FpsRange getSupportedRefreshRateRange() const EXCLUDES(mLock) { Loading @@ -208,10 +217,6 @@ public: std::optional<Fps> onKernelTimerChanged(std::optional<DisplayModeId> desiredActiveModeId, bool timerExpired) const EXCLUDES(mLock); // Returns the highest refresh rate according to the current policy. May change at runtime. Only // uses the primary range, not the app request range. DisplayModePtr getMaxRefreshRateByPolicy() const EXCLUDES(mLock); void setActiveModeId(DisplayModeId) EXCLUDES(mLock) REQUIRES(kMainThreadContext); // See mActiveModeIt for thread safety. Loading Loading @@ -343,7 +348,7 @@ private: // See mActiveModeIt for thread safety. DisplayModeIterator getActiveModeItLocked() const REQUIRES(mLock); std::pair<DisplayModePtr, GlobalSignals> getBestRefreshRateLocked( std::pair<std::vector<RefreshRateRanking>, GlobalSignals> getRankedRefreshRatesLocked( const std::vector<LayerRequirement>&, GlobalSignals) const REQUIRES(mLock); // Returns number of display frames and remainder when dividing the layer refresh period by Loading @@ -356,12 +361,23 @@ private: // Returns the highest refresh rate according to the current policy. May change at runtime. Only // uses the primary range, not the app request range. const DisplayModePtr& getMaxRefreshRateByPolicyLocked() const REQUIRES(mLock); const DisplayModePtr& getMaxRefreshRateByPolicyLocked(int anchorGroup) const REQUIRES(mLock); struct RefreshRateScoreComparator; enum class RefreshRateOrder { Ascending, Descending }; // Returns the rankings in RefreshRateOrder. May change at runtime. // Only uses the primary range, not the app request range. std::vector<RefreshRateRanking> getRefreshRatesByPolicyLocked(std::optional<int> anchorGroupOpt, RefreshRateOrder) const REQUIRES(mLock); const Policy* getCurrentPolicyLocked() const REQUIRES(mLock); bool isPolicyValidLocked(const Policy& policy) const REQUIRES(mLock); // Returns the refresh rate score as a ratio to max refresh rate, which has a score of 1. float calculateRefreshRateScoreForFps(Fps refreshRate) const REQUIRES(mLock); // calculates a score for a layer. Used to determine the display refresh rate // and the frame rate override for certains applications. float calculateLayerScoreLocked(const LayerRequirement&, Fps refreshRate, Loading Loading @@ -410,11 +426,11 @@ private: const Config mConfig; bool mSupportsFrameRateOverrideByContent; struct GetBestRefreshRateCache { struct GetRankedRefreshRatesCache { std::pair<std::vector<LayerRequirement>, GlobalSignals> arguments; std::pair<DisplayModePtr, GlobalSignals> result; std::pair<std::vector<RefreshRateRanking>, GlobalSignals> result; }; mutable std::optional<GetBestRefreshRateCache> mGetBestRefreshRateCache GUARDED_BY(mLock); mutable std::optional<GetRankedRefreshRatesCache> mGetRankedRefreshRatesCache 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 +7 −4 Original line number Diff line number Diff line Loading @@ -674,7 +674,9 @@ auto Scheduler::applyPolicy(S Policy::*statePtr, T&& newState) -> GlobalSignals if (currentState == newState) return {}; currentState = std::forward<T>(newState); std::tie(newMode, consideredSignals) = chooseDisplayMode(); const auto [rankings, signals] = getRankedDisplayModes(); newMode = rankings.front().displayModePtr; consideredSignals = signals; frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps()); if (mPolicy.mode == newMode) { Loading @@ -699,7 +701,8 @@ auto Scheduler::applyPolicy(S Policy::*statePtr, T&& newState) -> GlobalSignals return consideredSignals; } auto Scheduler::chooseDisplayMode() -> std::pair<DisplayModePtr, GlobalSignals> { auto Scheduler::getRankedDisplayModes() -> std::pair<std::vector<RefreshRateRanking>, GlobalSignals> { ATRACE_CALL(); const auto configs = holdRefreshRateConfigs(); Loading @@ -712,14 +715,14 @@ auto Scheduler::chooseDisplayMode() -> std::pair<DisplayModePtr, GlobalSignals> .idle = mPolicy.idleTimer == TimerState::Expired, .powerOnImminent = powerOnImminent}; return configs->getBestRefreshRate(mPolicy.contentRequirements, signals); return configs->getRankedRefreshRates(mPolicy.contentRequirements, signals); } DisplayModePtr Scheduler::getPreferredDisplayMode() { std::lock_guard<std::mutex> lock(mPolicyLock); // Make sure the stored mode is up to date. if (mPolicy.mode) { mPolicy.mode = chooseDisplayMode().first; mPolicy.mode = getRankedDisplayModes().first.front().displayModePtr; } return mPolicy.mode; } Loading
services/surfaceflinger/Scheduler/Scheduler.h +4 −2 Original line number Diff line number Diff line Loading @@ -269,8 +269,10 @@ private: template <typename S, typename T> GlobalSignals applyPolicy(S Policy::*, T&&) EXCLUDES(mPolicyLock); // Returns the display mode that fulfills the policy, and the signals that were considered. std::pair<DisplayModePtr, GlobalSignals> chooseDisplayMode() REQUIRES(mPolicyLock); // Returns the list of display modes in descending order of their priority that fulfills the // policy, and the signals that were considered. std::pair<std::vector<RefreshRateRanking>, GlobalSignals> getRankedDisplayModes() REQUIRES(mPolicyLock); bool updateFrameRateOverrides(GlobalSignals, Fps displayRefreshRate) REQUIRES(mPolicyLock); Loading
services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -350,7 +350,7 @@ void SchedulerFuzzer::fuzzRefreshRateConfigs() { const RefreshRateConfigs::GlobalSignals globalSignals = {.touch = false, .idle = false}; std::vector<LayerRequirement> layers = {{.weight = mFdp.ConsumeFloatingPoint<float>()}}; refreshRateConfigs.getBestRefreshRate(layers, globalSignals); refreshRateConfigs.getRankedRefreshRates(layers, globalSignals); layers[0].name = mFdp.ConsumeRandomLengthString(kRandomStringLength); layers[0].ownerUid = mFdp.ConsumeIntegral<uint16_t>(); Loading