Merge "SF: Remove BufferStateLayer class"
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 1df60a5..f567205 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);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index a7a08bf..bcd2b43 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -813,16 +813,37 @@
enableHalVirtualDisplays(true);
}
- // Process any initial hotplug and resulting display changes.
+ // Process hotplug for displays connected at boot.
LOG_ALWAYS_FATAL_IF(!configureLocked(),
"Initial display configuration failed: HWC did not hotplug");
- processDisplayChangesLocked();
- const auto display = getDefaultDisplayDeviceLocked();
+ // Commit primary display.
+ sp<const DisplayDevice> display;
+ if (const auto indexOpt = mCurrentState.getDisplayIndex(getPrimaryDisplayIdLocked())) {
+ const auto& displays = mCurrentState.displays;
+
+ const auto& token = displays.keyAt(*indexOpt);
+ const auto& state = displays.valueAt(*indexOpt);
+
+ processDisplayAdded(token, state);
+ mDrawingState.displays.add(token, state);
+
+ display = getDefaultDisplayDeviceLocked();
+ }
+
LOG_ALWAYS_FATAL_IF(!display, "Failed to configure the primary display");
LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(display->getPhysicalId()),
"Primary display is disconnected");
+ // TODO(b/241285876): The Scheduler needlessly depends on creating the CompositionEngine part of
+ // the DisplayDevice, hence the above commit of the primary display. Remove that special case by
+ // initializing the Scheduler after configureLocked, once decoupled from DisplayDevice.
+ initScheduler(display);
+ dispatchDisplayHotplugEvent(display->getPhysicalId(), true);
+
+ // Commit secondary display(s).
+ processDisplayChangesLocked();
+
// initialize our drawing state
mDrawingState = mCurrentState;
@@ -2952,10 +2973,13 @@
LOG_FATAL_IF(!displaySurface);
auto display = setupNewDisplayDeviceInternal(displayToken, std::move(compositionDisplay), state,
displaySurface, producer);
- if (display->isPrimary()) {
- initScheduler(display);
- }
- if (!state.isVirtual()) {
+
+ if (mScheduler && !display->isVirtual()) {
+ // Display modes are reloaded on hotplug reconnect.
+ if (display->isPrimary()) {
+ mScheduler->setRefreshRateConfigs(display->holdRefreshRateConfigs());
+ }
+
dispatchDisplayHotplugEvent(display->getPhysicalId(), true);
}
@@ -3367,15 +3391,9 @@
mScheduler->onFrameRateOverridesChanged(mAppConnectionHandle, displayId);
}
-void SurfaceFlinger::initScheduler(const sp<DisplayDevice>& display) {
- if (mScheduler) {
- // If the scheduler is already initialized, this means that we received
- // a hotplug(connected) on the primary display. In that case we should
- // update the scheduler with the most recent display information.
- ALOGW("Scheduler already initialized, updating instead");
- mScheduler->setRefreshRateConfigs(display->holdRefreshRateConfigs());
- return;
- }
+void SurfaceFlinger::initScheduler(const sp<const DisplayDevice>& display) {
+ LOG_ALWAYS_FATAL_IF(mScheduler);
+
const auto currRefreshRate = display->getActiveMode()->getFps();
mRefreshRateStats = std::make_unique<scheduler::RefreshRateStats>(*mTimeStats, currRefreshRate,
hal::PowerMode::OFF);
@@ -7076,7 +7094,7 @@
mRegionSamplingThread->onCompositionComplete(mScheduler->getScheduledFrameTime());
}
-void SurfaceFlinger::onActiveDisplaySizeChanged(const sp<DisplayDevice>& activeDisplay) {
+void SurfaceFlinger::onActiveDisplaySizeChanged(const sp<const DisplayDevice>& activeDisplay) {
mScheduler->onActiveDisplayAreaChanged(activeDisplay->getWidth() * activeDisplay->getHeight());
getRenderEngine().onActiveDisplaySizeChanged(activeDisplay->getSize());
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 0daf71d..1f8874d 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -373,7 +373,20 @@
const LayerVector::StateSet stateSet = LayerVector::StateSet::Invalid;
LayerVector layersSortedByZ;
- DefaultKeyedVector< wp<IBinder>, DisplayDeviceState> displays;
+
+ // TODO(b/241285876): Replace deprecated DefaultKeyedVector with ftl::SmallMap.
+ DefaultKeyedVector<wp<IBinder>, DisplayDeviceState> displays;
+
+ std::optional<size_t> getDisplayIndex(PhysicalDisplayId displayId) const {
+ for (size_t i = 0; i < displays.size(); i++) {
+ const auto& state = displays.valueAt(i);
+ if (state.physical && state.physical->id == displayId) {
+ return i;
+ }
+ }
+
+ return {};
+ }
bool colorMatrixChanged = true;
mat4 colorMatrix;
@@ -694,7 +707,7 @@
void commitInputWindowCommands() REQUIRES(mStateLock);
void updateCursorAsync();
- void initScheduler(const sp<DisplayDevice>& display) REQUIRES(mStateLock);
+ void initScheduler(const sp<const DisplayDevice>&) REQUIRES(mStateLock);
void updatePhaseConfiguration(const Fps&) REQUIRES(mStateLock);
void setVsyncConfig(const VsyncModulator::VsyncConfig&, nsecs_t vsyncPeriod);
@@ -1026,7 +1039,7 @@
void onActiveDisplayChangedLocked(const sp<DisplayDevice>& activeDisplay)
REQUIRES(mStateLock, kMainThreadContext);
- void onActiveDisplaySizeChanged(const sp<DisplayDevice>& activeDisplay);
+ void onActiveDisplaySizeChanged(const sp<const DisplayDevice>&);
/*
* Debugging & dumpsys
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
index cb940b3..66bac44 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
@@ -350,7 +350,7 @@
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>();
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 5d9b2a8..a706c4b 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -41,6 +41,7 @@
struct TestableRefreshRateConfigs : RefreshRateConfigs {
using RefreshRateConfigs::RefreshRateConfigs;
+ using RefreshRateConfigs::RefreshRateOrder;
void setActiveModeId(DisplayModeId modeId) {
ftl::FakeGuard guard(kMainThreadContext);
@@ -67,19 +68,30 @@
return getMinRefreshRateByPolicyLocked();
}
+ DisplayModePtr getMaxRefreshRateByPolicy() const {
+ std::lock_guard lock(mLock);
+ return getMaxRefreshRateByPolicyLocked(getActiveModeItLocked()->second->getGroup());
+ }
+
+ std::vector<RefreshRateRanking> getRefreshRatesByPolicy(
+ std::optional<int> anchorGroupOpt, RefreshRateOrder refreshRateOrder) const {
+ std::lock_guard lock(mLock);
+ return RefreshRateConfigs::getRefreshRatesByPolicyLocked(anchorGroupOpt, refreshRateOrder);
+ }
+
const std::vector<Fps>& knownFrameRates() const { return mKnownFrameRates; }
- using RefreshRateConfigs::GetBestRefreshRateCache;
- auto& mutableGetBestRefreshRateCache() { return mGetBestRefreshRateCache; }
+ using RefreshRateConfigs::GetRankedRefreshRatesCache;
+ auto& mutableGetRankedRefreshRatesCache() { return mGetRankedRefreshRatesCache; }
- auto getBestRefreshRateAndSignals(const std::vector<LayerRequirement>& layers,
- GlobalSignals signals) const {
- return RefreshRateConfigs::getBestRefreshRate(layers, signals);
+ auto getRankedRefreshRatesAndSignals(const std::vector<LayerRequirement>& layers,
+ GlobalSignals signals) const {
+ return RefreshRateConfigs::getRankedRefreshRates(layers, signals);
}
DisplayModePtr getBestRefreshRate(const std::vector<LayerRequirement>& layers = {},
GlobalSignals signals = {}) const {
- return getBestRefreshRateAndSignals(layers, signals).first;
+ return getRankedRefreshRatesAndSignals(layers, signals).first.front().displayModePtr;
}
};
@@ -977,16 +989,116 @@
EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
}
+TEST_F(RefreshRateConfigsTest, getMaxRefreshRatesByPolicy) {
+ // The kModes_30_60_90 contains two kMode72_G1, kMode120_G1 which are from the
+ // different group.
+ TestableRefreshRateConfigs configs(kModes_30_60_90, kModeId60);
+ const std::vector<RefreshRateRanking>& expectedRefreshRates = {RefreshRateRanking{kMode90},
+ RefreshRateRanking{kMode60},
+ RefreshRateRanking{kMode30}};
+
+ const std::vector<RefreshRateRanking>& refreshRates =
+ configs.getRefreshRatesByPolicy(configs.getActiveMode().getGroup(),
+ TestableRefreshRateConfigs::RefreshRateOrder::
+ Descending);
+
+ ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size());
+ for (size_t i = 0; i < expectedRefreshRates.size(); ++i) {
+ EXPECT_EQ(expectedRefreshRates[i].displayModePtr, refreshRates[i].displayModePtr)
+ << "Expected fps " << expectedRefreshRates[i].displayModePtr->getFps().getIntValue()
+ << " Actual fps " << refreshRates[i].displayModePtr->getFps().getIntValue();
+ }
+}
+
+TEST_F(RefreshRateConfigsTest, getMinRefreshRatesByPolicy) {
+ // The kModes_30_60_90 contains two kMode72_G1, kMode120_G1 which are from the
+ // different group.
+ TestableRefreshRateConfigs configs(kModes_30_60_90, kModeId60);
+ const std::vector<RefreshRateRanking>& expectedRefreshRates = {RefreshRateRanking{kMode30},
+ RefreshRateRanking{kMode60},
+ RefreshRateRanking{kMode90}};
+
+ const std::vector<RefreshRateRanking>& refreshRates =
+ configs.getRefreshRatesByPolicy(configs.getActiveMode().getGroup(),
+ TestableRefreshRateConfigs::RefreshRateOrder::
+ Ascending);
+
+ ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size());
+ for (size_t i = 0; i < expectedRefreshRates.size(); ++i) {
+ EXPECT_EQ(expectedRefreshRates[i].displayModePtr, refreshRates[i].displayModePtr)
+ << "Expected fps " << expectedRefreshRates[i].displayModePtr->getFps().getIntValue()
+ << " Actual fps " << refreshRates[i].displayModePtr->getFps().getIntValue();
+ }
+}
+
+TEST_F(RefreshRateConfigsTest, getMinRefreshRatesByPolicyOutsideTheGroup) {
+ // The kModes_30_60_90 contains two kMode72_G1, kMode120_G1 which are from the
+ // different group.
+ TestableRefreshRateConfigs configs(kModes_30_60_90, kModeId72);
+ const std::vector<RefreshRateRanking>& expectedRefreshRates = {RefreshRateRanking{kMode30},
+ RefreshRateRanking{kMode60},
+ RefreshRateRanking{kMode90}};
+
+ EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {30_Hz, 90_Hz}, {30_Hz, 90_Hz}}), 0);
+
+ const std::vector<RefreshRateRanking>& refreshRates =
+ configs.getRefreshRatesByPolicy(/*anchorGroupOpt*/ std::nullopt,
+ TestableRefreshRateConfigs::RefreshRateOrder::
+ Ascending);
+
+ ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size());
+ for (size_t i = 0; i < expectedRefreshRates.size(); ++i) {
+ EXPECT_EQ(expectedRefreshRates[i].displayModePtr, refreshRates[i].displayModePtr)
+ << "Expected fps " << expectedRefreshRates[i].displayModePtr->getFps().getIntValue()
+ << " Actual fps " << refreshRates[i].displayModePtr->getFps().getIntValue();
+ }
+}
+
+TEST_F(RefreshRateConfigsTest, getMaxRefreshRatesByPolicyOutsideTheGroup) {
+ // The kModes_30_60_90 contains two kMode72_G1, kMode120_G1 which are from the
+ // different group.
+ TestableRefreshRateConfigs configs(kModes_30_60_90, kModeId72);
+ const std::vector<RefreshRateRanking>& expectedRefreshRates = {RefreshRateRanking{kMode90},
+ RefreshRateRanking{kMode60},
+ RefreshRateRanking{kMode30}};
+
+ EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {30_Hz, 90_Hz}, {30_Hz, 90_Hz}}), 0);
+
+ const std::vector<RefreshRateRanking>& refreshRates =
+ configs.getRefreshRatesByPolicy(/*anchorGroupOpt*/ std::nullopt,
+ TestableRefreshRateConfigs::RefreshRateOrder::
+ Descending);
+
+ ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size());
+ for (size_t i = 0; i < expectedRefreshRates.size(); ++i) {
+ EXPECT_EQ(expectedRefreshRates[i].displayModePtr, refreshRates[i].displayModePtr)
+ << "Expected fps " << expectedRefreshRates[i].displayModePtr->getFps().getIntValue()
+ << " Actual fps " << refreshRates[i].displayModePtr->getFps().getIntValue();
+ }
+}
+
TEST_F(RefreshRateConfigsTest, powerOnImminentConsidered) {
RefreshRateConfigs configs(kModes_60_90, kModeId60);
+ std::vector<RefreshRateRanking> expectedRefreshRates = {RefreshRateRanking{kMode90},
+ RefreshRateRanking{kMode60}};
- auto [refreshRate, signals] = configs.getBestRefreshRate({}, {});
+ auto [refreshRates, signals] = configs.getRankedRefreshRates({}, {});
EXPECT_FALSE(signals.powerOnImminent);
- EXPECT_EQ(kMode90, refreshRate);
+ ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size());
+ for (size_t i = 0; i < expectedRefreshRates.size(); ++i) {
+ EXPECT_EQ(expectedRefreshRates[i].displayModePtr, refreshRates[i].displayModePtr)
+ << "Expected fps " << expectedRefreshRates[i].displayModePtr->getFps().getIntValue()
+ << " Actual fps " << refreshRates[i].displayModePtr->getFps().getIntValue();
+ }
- std::tie(refreshRate, signals) = configs.getBestRefreshRate({}, {.powerOnImminent = true});
+ std::tie(refreshRates, signals) = configs.getRankedRefreshRates({}, {.powerOnImminent = true});
EXPECT_TRUE(signals.powerOnImminent);
- EXPECT_EQ(kMode90, refreshRate);
+ ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size());
+ for (size_t i = 0; i < expectedRefreshRates.size(); ++i) {
+ EXPECT_EQ(expectedRefreshRates[i].displayModePtr, refreshRates[i].displayModePtr)
+ << "Expected fps " << expectedRefreshRates[i].displayModePtr->getFps().getIntValue()
+ << " Actual fps " << refreshRates[i].displayModePtr->getFps().getIntValue();
+ }
std::vector<LayerRequirement> layers = {{.weight = 1.f}};
auto& lr1 = layers[0];
@@ -994,22 +1106,35 @@
lr1.desiredRefreshRate = 60_Hz;
lr1.name = "60Hz ExplicitExactOrMultiple";
- std::tie(refreshRate, signals) = configs.getBestRefreshRate(layers, {.powerOnImminent = false});
- EXPECT_FALSE(signals.powerOnImminent);
- EXPECT_EQ(kMode60, refreshRate);
-
- std::tie(refreshRate, signals) = configs.getBestRefreshRate(layers, {.powerOnImminent = true});
+ std::tie(refreshRates, signals) =
+ configs.getRankedRefreshRates(layers, {.powerOnImminent = true});
EXPECT_TRUE(signals.powerOnImminent);
- EXPECT_EQ(kMode90, refreshRate);
+ ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size());
+ for (size_t i = 0; i < expectedRefreshRates.size(); ++i) {
+ EXPECT_EQ(expectedRefreshRates[i].displayModePtr, refreshRates[i].displayModePtr)
+ << "Expected fps " << expectedRefreshRates[i].displayModePtr->getFps().getIntValue()
+ << " Actual fps " << refreshRates[i].displayModePtr->getFps().getIntValue();
+ }
+
+ expectedRefreshRates = {RefreshRateRanking{kMode60}, RefreshRateRanking{kMode90}};
+ std::tie(refreshRates, signals) =
+ configs.getRankedRefreshRates(layers, {.powerOnImminent = false});
+ EXPECT_FALSE(signals.powerOnImminent);
+ ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size());
+ for (size_t i = 0; i < expectedRefreshRates.size(); ++i) {
+ EXPECT_EQ(expectedRefreshRates[i].displayModePtr, refreshRates[i].displayModePtr)
+ << "Expected fps " << expectedRefreshRates[i].displayModePtr->getFps().getIntValue()
+ << " Actual fps " << refreshRates[i].displayModePtr->getFps().getIntValue();
+ }
}
TEST_F(RefreshRateConfigsTest, touchConsidered) {
RefreshRateConfigs configs(kModes_60_90, kModeId60);
- auto [_, signals] = configs.getBestRefreshRate({}, {});
+ auto [_, signals] = configs.getRankedRefreshRates({}, {});
EXPECT_FALSE(signals.touch);
- std::tie(std::ignore, signals) = configs.getBestRefreshRate({}, {.touch = true});
+ std::tie(std::ignore, signals) = configs.getRankedRefreshRates({}, {.touch = true});
EXPECT_TRUE(signals.touch);
std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}};
@@ -1022,16 +1147,16 @@
lr2.vote = LayerVoteType::Heuristic;
lr2.desiredRefreshRate = 60_Hz;
lr2.name = "60Hz Heuristic";
- std::tie(std::ignore, signals) = configs.getBestRefreshRate(layers, {.touch = true});
+ std::tie(std::ignore, signals) = configs.getRankedRefreshRates(layers, {.touch = true});
EXPECT_TRUE(signals.touch);
lr1.vote = LayerVoteType::ExplicitDefault;
lr1.desiredRefreshRate = 60_Hz;
- lr1.name = "60Hz ExplicitExactOrMultiple";
+ lr1.name = "60Hz ExplicitDefault";
lr2.vote = LayerVoteType::Heuristic;
lr2.desiredRefreshRate = 60_Hz;
lr2.name = "60Hz Heuristic";
- std::tie(std::ignore, signals) = configs.getBestRefreshRate(layers, {.touch = true});
+ std::tie(std::ignore, signals) = configs.getRankedRefreshRates(layers, {.touch = true});
EXPECT_FALSE(signals.touch);
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -1040,16 +1165,16 @@
lr2.vote = LayerVoteType::Heuristic;
lr2.desiredRefreshRate = 60_Hz;
lr2.name = "60Hz Heuristic";
- std::tie(std::ignore, signals) = configs.getBestRefreshRate(layers, {.touch = true});
+ std::tie(std::ignore, signals) = configs.getRankedRefreshRates(layers, {.touch = true});
EXPECT_TRUE(signals.touch);
lr1.vote = LayerVoteType::ExplicitDefault;
lr1.desiredRefreshRate = 60_Hz;
- lr1.name = "60Hz ExplicitExactOrMultiple";
+ lr1.name = "60Hz ExplicitDefault";
lr2.vote = LayerVoteType::Heuristic;
lr2.desiredRefreshRate = 60_Hz;
lr2.name = "60Hz Heuristic";
- std::tie(std::ignore, signals) = configs.getBestRefreshRate(layers, {.touch = true});
+ std::tie(std::ignore, signals) = configs.getRankedRefreshRates(layers, {.touch = true});
EXPECT_FALSE(signals.touch);
}
@@ -1187,9 +1312,10 @@
lr.name = "60Hz ExplicitDefault";
lr.focused = true;
- const auto [mode, signals] = configs.getBestRefreshRate(layers, {.touch = true, .idle = true});
+ const auto [mode, signals] =
+ configs.getRankedRefreshRates(layers, {.touch = true, .idle = true});
- EXPECT_EQ(mode, kMode60);
+ EXPECT_EQ(mode.begin()->displayModePtr, kMode60);
EXPECT_FALSE(signals.touch);
}
@@ -1209,14 +1335,147 @@
EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers, {.idle = true}));
}
+TEST_F(RefreshRateConfigsTest, testDisplayModeOrdering) {
+ TestableRefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId60);
+
+ std::vector<LayerRequirement> layers = {{.weight = 1.f},
+ {.weight = 1.f},
+ {.weight = 1.f},
+ {.weight = 1.f},
+ {.weight = 1.f}};
+ auto& lr1 = layers[0];
+ auto& lr2 = layers[1];
+ auto& lr3 = layers[2];
+ auto& lr4 = layers[3];
+ auto& lr5 = layers[4];
+
+ lr1.desiredRefreshRate = 90_Hz;
+ lr1.name = "90Hz";
+ lr1.focused = true;
+
+ lr2.desiredRefreshRate = 60_Hz;
+ lr2.name = "60Hz";
+ lr2.focused = true;
+
+ lr3.desiredRefreshRate = 72_Hz;
+ lr3.name = "72Hz";
+ lr3.focused = true;
+
+ lr4.desiredRefreshRate = 120_Hz;
+ lr4.name = "120Hz";
+ lr4.focused = true;
+
+ lr5.desiredRefreshRate = 30_Hz;
+ lr5.name = "30Hz";
+ lr5.focused = true;
+
+ std::vector<RefreshRateRanking> expectedRankings = {
+ RefreshRateRanking{kMode120}, RefreshRateRanking{kMode90}, RefreshRateRanking{kMode72},
+ RefreshRateRanking{kMode60}, RefreshRateRanking{kMode30},
+ };
+
+ std::vector<RefreshRateRanking> actualOrder =
+ configs.getRankedRefreshRatesAndSignals(layers, {}).first;
+ ASSERT_EQ(expectedRankings.size(), actualOrder.size());
+ for (size_t i = 0; i < expectedRankings.size(); ++i) {
+ EXPECT_EQ(expectedRankings[i].displayModePtr, actualOrder[i].displayModePtr)
+ << "Expected fps " << expectedRankings[i].displayModePtr->getFps().getIntValue()
+ << " Actual fps " << actualOrder[i].displayModePtr->getFps().getIntValue();
+ }
+
+ lr1.vote = LayerVoteType::Max;
+ lr1.name = "Max";
+
+ lr2.desiredRefreshRate = 60_Hz;
+ lr2.name = "60Hz";
+
+ lr3.desiredRefreshRate = 72_Hz;
+ lr3.name = "72Hz";
+
+ lr4.desiredRefreshRate = 90_Hz;
+ lr4.name = "90Hz";
+
+ lr5.desiredRefreshRate = 120_Hz;
+ lr5.name = "120Hz";
+
+ expectedRankings = {
+ RefreshRateRanking{kMode120}, RefreshRateRanking{kMode90}, RefreshRateRanking{kMode72},
+ RefreshRateRanking{kMode60}, RefreshRateRanking{kMode30},
+ };
+
+ actualOrder = configs.getRankedRefreshRatesAndSignals(layers, {}).first;
+
+ ASSERT_EQ(expectedRankings.size(), actualOrder.size());
+ for (size_t i = 0; i < expectedRankings.size(); ++i) {
+ EXPECT_EQ(expectedRankings[i].displayModePtr, actualOrder[i].displayModePtr)
+ << "Expected fps " << expectedRankings[i].displayModePtr->getFps().getIntValue()
+ << " Actual fps " << actualOrder[i].displayModePtr->getFps().getIntValue();
+ }
+
+ lr1.vote = LayerVoteType::Heuristic;
+ lr1.desiredRefreshRate = 30_Hz;
+ lr1.name = "30Hz";
+
+ lr2.desiredRefreshRate = 120_Hz;
+ lr2.name = "120Hz";
+
+ lr3.desiredRefreshRate = 60_Hz;
+ lr3.name = "60Hz";
+
+ lr5.desiredRefreshRate = 72_Hz;
+ lr5.name = "72Hz";
+
+ expectedRankings = {
+ RefreshRateRanking{kMode30}, RefreshRateRanking{kMode60}, RefreshRateRanking{kMode90},
+ RefreshRateRanking{kMode120}, RefreshRateRanking{kMode72},
+ };
+
+ actualOrder = configs.getRankedRefreshRatesAndSignals(layers, {}).first;
+ ASSERT_EQ(expectedRankings.size(), actualOrder.size());
+ for (size_t i = 0; i < expectedRankings.size(); ++i) {
+ EXPECT_EQ(expectedRankings[i].displayModePtr, actualOrder[i].displayModePtr)
+ << "Expected fps " << expectedRankings[i].displayModePtr->getFps().getIntValue()
+ << " Actual fps " << actualOrder[i].displayModePtr->getFps().getIntValue();
+ }
+
+ lr1.desiredRefreshRate = 120_Hz;
+ lr1.name = "120Hz";
+ lr1.weight = 0.0f;
+
+ lr2.desiredRefreshRate = 60_Hz;
+ lr2.name = "60Hz";
+ lr2.vote = LayerVoteType::NoVote;
+
+ lr3.name = "60Hz-2";
+ lr3.vote = LayerVoteType::Heuristic;
+
+ lr4.vote = LayerVoteType::ExplicitExact;
+
+ lr5.desiredRefreshRate = 120_Hz;
+ lr5.name = "120Hz-2";
+
+ expectedRankings = {
+ RefreshRateRanking{kMode90}, RefreshRateRanking{kMode60}, RefreshRateRanking{kMode120},
+ RefreshRateRanking{kMode72}, RefreshRateRanking{kMode30},
+ };
+
+ actualOrder = configs.getRankedRefreshRatesAndSignals(layers, {}).first;
+ ASSERT_EQ(expectedRankings.size(), actualOrder.size());
+ for (size_t i = 0; i < expectedRankings.size(); ++i) {
+ EXPECT_EQ(expectedRankings[i].displayModePtr, actualOrder[i].displayModePtr)
+ << "Expected fps " << expectedRankings[i].displayModePtr->getFps().getIntValue()
+ << " Actual fps " << actualOrder[i].displayModePtr->getFps().getIntValue();
+ }
+}
+
TEST_F(RefreshRateConfigsTest,
getBestRefreshRate_withDisplayManagerRequestingSingleRate_onlySwitchesRatesForExplicitFocusedLayers) {
TestableRefreshRateConfigs configs(kModes_60_90, kModeId90);
EXPECT_GE(configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}, {60_Hz, 90_Hz}}), 0);
- const auto [mode, signals] = configs.getBestRefreshRateAndSignals({}, {});
- EXPECT_EQ(mode, kMode90);
+ const auto [mode, signals] = configs.getRankedRefreshRatesAndSignals({}, {});
+ EXPECT_EQ(mode.front().displayModePtr, kMode90);
EXPECT_FALSE(signals.touch);
std::vector<LayerRequirement> layers = {{.weight = 1.f}};
@@ -1593,11 +1852,12 @@
layers[0].desiredRefreshRate = 90_Hz;
const auto [refreshRate, signals] =
- configs.getBestRefreshRateAndSignals(layers, {.touch = touchActive, .idle = true});
+ configs.getRankedRefreshRatesAndSignals(layers,
+ {.touch = touchActive, .idle = true});
// Refresh rate will be chosen by either touch state or idle state.
EXPECT_EQ(!touchActive, signals.idle);
- return refreshRate->getId();
+ return refreshRate.front().displayModePtr->getId();
};
EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 90_Hz}, {60_Hz, 90_Hz}}), 0);
@@ -1756,24 +2016,26 @@
using GlobalSignals = RefreshRateConfigs::GlobalSignals;
const auto args = std::make_pair(std::vector<LayerRequirement>{},
GlobalSignals{.touch = true, .idle = true});
- const auto result = std::make_pair(kMode90, GlobalSignals{.touch = true});
- configs.mutableGetBestRefreshRateCache() = {args, result};
+ const auto result = std::make_pair(std::vector<RefreshRateRanking>{RefreshRateRanking{kMode90}},
+ GlobalSignals{.touch = true});
- EXPECT_EQ(result, configs.getBestRefreshRateAndSignals(args.first, args.second));
+ configs.mutableGetRankedRefreshRatesCache() = {args, result};
+
+ EXPECT_EQ(result, configs.getRankedRefreshRatesAndSignals(args.first, args.second));
}
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_WritesCache) {
TestableRefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId60);
- EXPECT_FALSE(configs.mutableGetBestRefreshRateCache());
+ EXPECT_FALSE(configs.mutableGetRankedRefreshRatesCache());
std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 0.5f}};
RefreshRateConfigs::GlobalSignals globalSignals{.touch = true, .idle = true};
- const auto result = configs.getBestRefreshRateAndSignals(layers, globalSignals);
+ const auto result = configs.getRankedRefreshRatesAndSignals(layers, globalSignals);
- const auto& cache = configs.mutableGetBestRefreshRateCache();
+ const auto& cache = configs.mutableGetRankedRefreshRatesCache();
ASSERT_TRUE(cache);
EXPECT_EQ(cache->arguments, std::make_pair(layers, globalSignals));