diff options
author | Ady Abraham <adyabr@google.com> | 2022-08-13 05:12:13 +0000 |
---|---|---|
committer | Ady Abraham <adyabr@google.com> | 2022-08-25 22:15:24 +0000 |
commit | fad66b2c0b0dba8e6df0e023b5f199dbf0598968 (patch) | |
tree | c8a0d70cdda8d25fec7306b3e29342b636de930e | |
parent | 2c23a2ee8f19f3a73ddbaddfb91566488e55e73c (diff) | |
download | native-fad66b2c0b0dba8e6df0e023b5f199dbf0598968.tar.gz |
SF: fix refresh rate scoring when frameRateMultipleThreshold is used
We can't exclude layers that are below the frameRateMultipleThreshold
when scoring the higher refresh rates (the ones above the threshold)
as it creates gives the lower refresh rates a higher score (as there are
more layers that are allowed to score them). Instead we use a different
approach which first scores the refresh rates based on all the layers
but the fixed source ones, and then we add the fixed source ones for the
refresh rates below the thresholds and for the above ones only when other
layers already scored them.
Bug: 242283390
Test: newly added unit tests scenarios
SF: layers above the frameRateMultipleThreshold should always be counted
An additional fix on top of ae2e3c741f0d15d0ed64afd2df93e8c4b2d76cfb
which also include layers that have a desired refresh
rate that was calculated hueristically and matches the max refresh rate.
Bug: 242283390
Test: newly added unit tests scenarios
Change-Id: I85534a3e004f372349dbf923ee6013855a54e4fa
Merged-In: Ibe30ddd306265507ceedff6a6a725dadadc50af2
Merged-In: I85534a3e004f372349dbf923ee6013855a54e4fa
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) { |