From fad66b2c0b0dba8e6df0e023b5f199dbf0598968 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Sat, 13 Aug 2022 05:12:13 +0000 Subject: 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 --- .../Scheduler/RefreshRateConfigs.cpp | 142 ++++++++++++++------- .../surfaceflinger/Scheduler/RefreshRateConfigs.h | 3 - .../tests/unittests/RefreshRateConfigsTest.cpp | 45 ++++++- 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 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(std::round(score * 100))); + ATRACE_INT(name.c_str(), static_cast(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 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& auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector& layers, GlobalSignals signals) const -> std::pair { + using namespace fps_approx_ops; ATRACE_CALL(); ALOGV("%s: %zu layers", __func__, layers.size()); @@ -409,7 +385,7 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vectorgetGroup() == mActiveModeIt->second->getGroup(); @@ -451,18 +427,92 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vectorgetFps(), 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::vectorgetFps()).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 layers = {{.weight = 1.f}, {.weight = 1.f}}; + std::vector 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) { -- cgit v1.2.3-59-g8ed1b