summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-08-30 23:21:35 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-08-30 23:21:35 +0000
commit86d098ecf01c3401061aad14b2df4c43748d08df (patch)
treec8a0d70cdda8d25fec7306b3e29342b636de930e
parentf9e6004fffd9ef8a518f2863b31a38ee027fa11d (diff)
parentfad66b2c0b0dba8e6df0e023b5f199dbf0598968 (diff)
downloadnative-86d098ecf01c3401061aad14b2df4c43748d08df.tar.gz
Snap for 9010110 from fad66b2c0b0dba8e6df0e023b5f199dbf0598968 to tm-qpr1-release
Change-Id: I81f03e13a3cce38abb56bf10e9dcaa21922bb218
-rw-r--r--services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp142
-rw-r--r--services/surfaceflinger/Scheduler/RefreshRateConfigs.h3
-rw-r--r--services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp45
3 files changed, 140 insertions, 50 deletions
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index ca8349636b..a48c921378 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -40,22 +40,26 @@ namespace {
struct RefreshRateScore {
DisplayModeIterator modeIt;
- float score;
+ float overallScore;
+ struct {
+ float modeBelowThreshold;
+ float modeAboveThreshold;
+ } 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, score] = current;
+ const auto& [modeIt, overallScore, _] = current;
std::string name = to_string(modeIt->second->getFps());
- ALOGV("%s scores %.2f", name.c_str(), score);
+ ALOGV("%s scores %.2f", name.c_str(), overallScore);
- ATRACE_INT(name.c_str(), static_cast<int>(std::round(score * 100)));
+ ATRACE_INT(name.c_str(), static_cast<int>(std::round(overallScore * 100)));
constexpr float kEpsilon = 0.0001f;
- return score > max.score * (1 + kEpsilon);
+ return overallScore > max.overallScore * (1 + kEpsilon);
});
return it->modeIt->second;
@@ -151,31 +155,6 @@ std::pair<nsecs_t, nsecs_t> RefreshRateConfigs::getDisplayFrames(nsecs_t layerPe
return {quotient, remainder};
}
-bool RefreshRateConfigs::isVoteAllowed(const LayerRequirement& layer, Fps refreshRate) const {
- using namespace fps_approx_ops;
-
- switch (layer.vote) {
- case LayerVoteType::ExplicitExactOrMultiple:
- case LayerVoteType::Heuristic:
- if (mConfig.frameRateMultipleThreshold != 0 &&
- refreshRate >= Fps::fromValue(mConfig.frameRateMultipleThreshold) &&
- layer.desiredRefreshRate < Fps::fromValue(mConfig.frameRateMultipleThreshold / 2)) {
- // Don't vote high refresh rates past the threshold for layers with a low desired
- // refresh rate. For example, desired 24 fps with 120 Hz threshold means no vote for
- // 120 Hz, but desired 60 fps should have a vote.
- return false;
- }
- break;
- case LayerVoteType::ExplicitDefault:
- case LayerVoteType::ExplicitExact:
- case LayerVoteType::Max:
- case LayerVoteType::Min:
- case LayerVoteType::NoVote:
- break;
- }
- return true;
-}
-
float RefreshRateConfigs::calculateNonExactMatchingLayerScoreLocked(const LayerRequirement& layer,
Fps refreshRate) const {
constexpr float kScoreForFractionalPairs = .8f;
@@ -240,10 +219,6 @@ float RefreshRateConfigs::calculateNonExactMatchingLayerScoreLocked(const LayerR
float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& layer, Fps refreshRate,
bool isSeamlessSwitch) const {
- if (!isVoteAllowed(layer, refreshRate)) {
- return 0;
- }
-
// Slightly prefer seamless switches.
constexpr float kSeamedSwitchPenalty = 0.95f;
const float seamlessness = isSeamlessSwitch ? 1.0f : kSeamedSwitchPenalty;
@@ -300,6 +275,7 @@ auto RefreshRateConfigs::getBestRefreshRate(const std::vector<LayerRequirement>&
auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequirement>& layers,
GlobalSignals signals) const
-> std::pair<DisplayModePtr, GlobalSignals> {
+ using namespace fps_approx_ops;
ATRACE_CALL();
ALOGV("%s: %zu layers", __func__, layers.size());
@@ -409,7 +385,7 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire
const auto weight = layer.weight;
- for (auto& [modeIt, score] : scores) {
+ for (auto& [modeIt, overallScore, fixedRateBelowThresholdLayersScore] : scores) {
const auto& [id, mode] = *modeIt;
const bool isSeamlessSwitch = mode->getGroup() == mActiveModeIt->second->getGroup();
@@ -451,18 +427,92 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire
continue;
}
- const auto layerScore =
+ const float layerScore =
calculateLayerScoreLocked(layer, mode->getFps(), isSeamlessSwitch);
- ALOGV("%s gives %s score of %.4f", formatLayerInfo(layer, weight).c_str(),
- to_string(mode->getFps()).c_str(), layerScore);
+ const float weightedLayerScore = weight * layerScore;
+
+ // Layer with fixed source has a special consideration which depends on the
+ // mConfig.frameRateMultipleThreshold. We don't want these layers to score
+ // refresh rates above the threshold, but we also don't want to favor the lower
+ // ones by having a greater number of layers scoring them. Instead, we calculate
+ // the score independently for these layers and later decide which
+ // refresh rates to add it. For example, desired 24 fps with 120 Hz threshold should not
+ // score 120 Hz, but desired 60 fps should contribute to the score.
+ const bool fixedSourceLayer = [](LayerVoteType vote) {
+ switch (vote) {
+ case LayerVoteType::ExplicitExactOrMultiple:
+ case LayerVoteType::Heuristic:
+ return true;
+ case LayerVoteType::NoVote:
+ case LayerVoteType::Min:
+ case LayerVoteType::Max:
+ case LayerVoteType::ExplicitDefault:
+ case LayerVoteType::ExplicitExact:
+ return false;
+ }
+ }(layer.vote);
+ const bool layerBelowThreshold = mConfig.frameRateMultipleThreshold != 0 &&
+ layer.desiredRefreshRate <
+ Fps::fromValue(mConfig.frameRateMultipleThreshold / 2);
+ if (fixedSourceLayer && layerBelowThreshold) {
+ const bool modeAboveThreshold =
+ mode->getFps() >= Fps::fromValue(mConfig.frameRateMultipleThreshold);
+ if (modeAboveThreshold) {
+ ALOGV("%s gives %s fixed source (above threshold) score of %.4f",
+ formatLayerInfo(layer, weight).c_str(), to_string(mode->getFps()).c_str(),
+ layerScore);
+ fixedRateBelowThresholdLayersScore.modeAboveThreshold += weightedLayerScore;
+ } else {
+ ALOGV("%s gives %s fixed source (below threshold) score of %.4f",
+ formatLayerInfo(layer, weight).c_str(), to_string(mode->getFps()).c_str(),
+ layerScore);
+ fixedRateBelowThresholdLayersScore.modeBelowThreshold += weightedLayerScore;
+ }
+ } else {
+ ALOGV("%s gives %s score of %.4f", formatLayerInfo(layer, weight).c_str(),
+ to_string(mode->getFps()).c_str(), layerScore);
+ overallScore += weightedLayerScore;
+ }
+ }
+ }
+
+ // We want to find the best refresh rate without the fixed source layers,
+ // so we could know whether we should add the modeAboveThreshold scores or not.
+ // If the best refresh rate is already above the threshold, it means that
+ // some non-fixed source layers already scored it, so we can just add the score
+ // for all fixed source layers, even the ones that are above the threshold.
+ const bool maxScoreAboveThreshold = [&] {
+ if (mConfig.frameRateMultipleThreshold == 0 || scores.empty()) {
+ return false;
+ }
+
+ const auto maxScoreIt =
+ std::max_element(scores.begin(), scores.end(),
+ [](RefreshRateScore max, RefreshRateScore current) {
+ const auto& [modeIt, overallScore, _] = current;
+ return overallScore > max.overallScore;
+ });
+ ALOGV("%s is the best refresh rate without fixed source layers. It is %s the threshold for "
+ "refresh rate multiples",
+ to_string(maxScoreIt->modeIt->second->getFps()).c_str(),
+ maxScoreAboveThreshold ? "above" : "below");
+ return maxScoreIt->modeIt->second->getFps() >=
+ Fps::fromValue(mConfig.frameRateMultipleThreshold);
+ }();
- score += weight * layerScore;
+ // Now we can add the fixed rate layers score
+ for (auto& [modeIt, overallScore, fixedRateBelowThresholdLayersScore] : scores) {
+ overallScore += fixedRateBelowThresholdLayersScore.modeBelowThreshold;
+ if (maxScoreAboveThreshold) {
+ overallScore += fixedRateBelowThresholdLayersScore.modeAboveThreshold;
}
+ ALOGV("%s adjusted overallScore is %.4f", to_string(modeIt->second->getFps()).c_str(),
+ overallScore);
}
- // Now that we scored all the refresh rates we need to pick the one that got the highest score.
- // In case of a tie we will pick the higher refresh rate if any of the layers wanted Max,
- // or the lower otherwise.
+ // 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());
@@ -471,7 +521,7 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire
// 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.score == 0; })) {
+ [](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};
@@ -575,7 +625,7 @@ RefreshRateConfigs::UidToFrameRateOverride RefreshRateConfigs::getFrameRateOverr
continue;
}
- for (auto& [_, score] : scores) {
+ for (auto& [_, score, _1] : scores) {
score = 0;
}
@@ -587,7 +637,7 @@ RefreshRateConfigs::UidToFrameRateOverride RefreshRateConfigs::getFrameRateOverr
LOG_ALWAYS_FATAL_IF(layer->vote != LayerVoteType::ExplicitDefault &&
layer->vote != LayerVoteType::ExplicitExactOrMultiple &&
layer->vote != LayerVoteType::ExplicitExact);
- for (auto& [modeIt, score] : scores) {
+ for (auto& [modeIt, score, _] : scores) {
constexpr bool isSeamlessSwitch = true;
const auto layerScore = calculateLayerScoreLocked(*layer, modeIt->second->getFps(),
isSeamlessSwitch);
@@ -605,7 +655,7 @@ RefreshRateConfigs::UidToFrameRateOverride RefreshRateConfigs::getFrameRateOverr
// If we never scored any layers, we don't have a preferred frame rate
if (std::all_of(scores.begin(), scores.end(),
- [](RefreshRateScore score) { return score.score == 0; })) {
+ [](RefreshRateScore score) { return score.overallScore == 0; })) {
continue;
}
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 05a8692f51..a79002e959 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -353,9 +353,6 @@ private:
const Policy* getCurrentPolicyLocked() const REQUIRES(mLock);
bool isPolicyValidLocked(const Policy& policy) const REQUIRES(mLock);
- // Returns whether the layer is allowed to vote for the given refresh rate.
- bool isVoteAllowed(const LayerRequirement&, Fps) const;
-
// 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,
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index fcde532b85..188fd58dea 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -564,9 +564,10 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes_mu
TestableRefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId60,
{.frameRateMultipleThreshold = 120});
- std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}, {.weight = 1.f}};
auto& lr1 = layers[0];
auto& lr2 = layers[1];
+ auto& lr3 = layers[2];
lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::ExplicitDefault;
@@ -639,6 +640,48 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes_mu
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.name = "90Hz ExplicitExactOrMultiple";
EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
+
+ lr1.desiredRefreshRate = 24_Hz;
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.name = "24Hz ExplicitExactOrMultiple";
+ lr2.vote = LayerVoteType::Max;
+ lr2.name = "Max";
+ EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers));
+
+ lr1.desiredRefreshRate = 24_Hz;
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.name = "24Hz ExplicitExactOrMultiple";
+ lr2.desiredRefreshRate = 120_Hz;
+ lr2.vote = LayerVoteType::ExplicitDefault;
+ lr2.name = "120Hz ExplicitDefault";
+ EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers));
+
+ lr1.desiredRefreshRate = 24_Hz;
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.name = "24Hz ExplicitExactOrMultiple";
+ lr2.desiredRefreshRate = 120_Hz;
+ lr2.vote = LayerVoteType::ExplicitExact;
+ lr2.name = "120Hz ExplicitExact";
+ EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers));
+
+ lr1.desiredRefreshRate = 10_Hz;
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.name = "30Hz ExplicitExactOrMultiple";
+ lr2.desiredRefreshRate = 120_Hz;
+ lr2.vote = LayerVoteType::Heuristic;
+ lr2.name = "120Hz ExplicitExact";
+ EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers));
+
+ lr1.desiredRefreshRate = 30_Hz;
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.name = "30Hz ExplicitExactOrMultiple";
+ lr2.desiredRefreshRate = 30_Hz;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr2.name = "30Hz ExplicitExactOrMultiple";
+ lr3.vote = LayerVoteType::Heuristic;
+ lr3.desiredRefreshRate = 120_Hz;
+ lr3.name = "120Hz Heuristic";
+ EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers));
}
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60) {