[MD] Return list of scored refresh rates based on overallscore.
The sorted list returns the refresh rates in the
descending order of priority and their
overallscore.
This overall score will be used and called for multiple displays
and will be used to make the final selection in the
DisplayModeController for all the displays.
BUG: 240743471
Test: atest libsurfaceflinger_unittest
Change-Id: I8355425e89452f5ce73858a6173c53be9f3753ef
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 00886f0..3cb052c 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -48,24 +48,6 @@
} 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) {
@@ -137,6 +119,34 @@
} // 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}",
@@ -218,6 +228,13 @@
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.
@@ -226,10 +243,7 @@
// 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) {
@@ -258,24 +272,24 @@
kNonExactMatchingPenalty;
}
-auto RefreshRateConfigs::getBestRefreshRate(const std::vector<LayerRequirement>& layers,
- GlobalSignals signals) const
- -> std::pair<DisplayModePtr, GlobalSignals> {
+auto RefreshRateConfigs::getRankedRefreshRates(const std::vector<LayerRequirement>& layers,
+ GlobalSignals signals) const
+ -> 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,
- GlobalSignals signals) const
- -> std::pair<DisplayModePtr, GlobalSignals> {
+auto RefreshRateConfigs::getRankedRefreshRatesLocked(const std::vector<LayerRequirement>& layers,
+ GlobalSignals signals) const
+ -> std::pair<std::vector<RefreshRateRanking>, GlobalSignals> {
using namespace fps_approx_ops;
ATRACE_CALL();
ALOGV("%s: %zu layers", __func__, layers.size());
@@ -285,8 +299,8 @@
// 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;
@@ -295,7 +309,6 @@
int explicitDefaultVoteLayers = 0;
int explicitExactOrMultipleVoteLayers = 0;
int explicitExact = 0;
- float maxExplicitWeight = 0;
int seamedFocusedLayers = 0;
for (const auto& layer : layers) {
@@ -311,15 +324,12 @@
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;
@@ -348,9 +358,9 @@
// 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
@@ -360,22 +370,22 @@
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
@@ -522,22 +532,29 @@
}
// 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};
}
}
@@ -545,8 +562,6 @@
// 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
@@ -557,15 +572,18 @@
}
}();
+ 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*>>
@@ -670,11 +688,13 @@
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());
}
@@ -715,16 +735,6 @@
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;
@@ -733,14 +743,41 @@
}
}
- 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;
@@ -760,9 +797,9 @@
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());
@@ -797,9 +834,9 @@
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);
@@ -843,7 +880,7 @@
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) {
@@ -858,7 +895,7 @@
if (policy && !isPolicyValidLocked(*policy)) {
return BAD_VALUE;
}
- mGetBestRefreshRateCache.reset();
+ mGetRankedRefreshRatesCache.reset();
Policy previousPolicy = *getCurrentPolicyLocked();
mOverridePolicy = policy;
if (*getCurrentPolicyLocked() == previousPolicy) {
@@ -958,7 +995,8 @@
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();
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 19bcb94..0642fcb 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -44,6 +44,15 @@
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;
/**
@@ -195,9 +204,9 @@
}
};
- // 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) {
@@ -208,10 +217,6 @@
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.
@@ -343,7 +348,7 @@
// 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
@@ -356,12 +361,23 @@
// 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,
@@ -410,11 +426,11 @@
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;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index ff6b461..6d68bac 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -674,7 +674,9 @@
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) {
@@ -699,7 +701,8 @@
return consideredSignals;
}
-auto Scheduler::chooseDisplayMode() -> std::pair<DisplayModePtr, GlobalSignals> {
+auto Scheduler::getRankedDisplayModes()
+ -> std::pair<std::vector<RefreshRateRanking>, GlobalSignals> {
ATRACE_CALL();
const auto configs = holdRefreshRateConfigs();
@@ -712,14 +715,14 @@
.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;
}
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index afb3459..9f3f4d9 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -269,8 +269,10 @@
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);