Loading services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +95 −46 Original line number Diff line number Diff line Loading @@ -40,22 +40,26 @@ namespace { struct RefreshRateScore { DisplayModeIterator modeIt; float score; float overallScore; struct { float belowThreshold; float aboveThreshold; } fixedRateLayersScore; }; 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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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()); Loading Loading @@ -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, fixedRateScore] : scores) { const auto& [id, mode] = *modeIt; const bool isSeamlessSwitch = mode->getGroup() == mActiveModeIt->second->getGroup(); Loading Loading @@ -451,18 +427,91 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire continue; } const auto layerScore = const float layerScore = calculateLayerScoreLocked(layer, mode->getFps(), isSeamlessSwitch); const float weightedLayerScore = weight * layerScore; // Layer with fixed source has a special consideration 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 layerAboveThreshold = mConfig.frameRateMultipleThreshold != 0 && mode->getFps() >= Fps::fromValue(mConfig.frameRateMultipleThreshold) && layer.desiredRefreshRate < Fps::fromValue(mConfig.frameRateMultipleThreshold / 2); if (fixedSourceLayer) { if (layerAboveThreshold) { ALOGV("%s gives %s fixed source (above threshold) score of %.4f", formatLayerInfo(layer, weight).c_str(), to_string(mode->getFps()).c_str(), layerScore); fixedRateScore.aboveThreshold += 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); fixedRateScore.belowThreshold += weightedLayerScore; } } else { ALOGV("%s gives %s score of %.4f", formatLayerInfo(layer, weight).c_str(), to_string(mode->getFps()).c_str(), layerScore); overallScore += weightedLayerScore; } } } score += weight * layerScore; // We want to find the best refresh rate without the fixed source layers, // so we could know whether we should add the aboveThreshold 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); }(); // Now we can add the fixed rate layers score for (auto& [modeIt, overallScore, fixedRateScore] : scores) { overallScore += fixedRateScore.belowThreshold; if (maxScoreAboveThreshold) { overallScore += fixedRateScore.aboveThreshold; } 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()); Loading @@ -471,7 +520,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}; Loading Loading @@ -575,7 +624,7 @@ RefreshRateConfigs::UidToFrameRateOverride RefreshRateConfigs::getFrameRateOverr continue; } for (auto& [_, score] : scores) { for (auto& [_, score, _1] : scores) { score = 0; } Loading @@ -587,7 +636,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); Loading @@ -605,7 +654,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; } Loading services/surfaceflinger/Scheduler/RefreshRateConfigs.h +0 −3 Original line number Diff line number Diff line Loading @@ -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, Loading services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +23 −0 Original line number Diff line number Diff line Loading @@ -639,6 +639,29 @@ 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)); } TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60) { Loading Loading
services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +95 −46 Original line number Diff line number Diff line Loading @@ -40,22 +40,26 @@ namespace { struct RefreshRateScore { DisplayModeIterator modeIt; float score; float overallScore; struct { float belowThreshold; float aboveThreshold; } fixedRateLayersScore; }; 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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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()); Loading Loading @@ -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, fixedRateScore] : scores) { const auto& [id, mode] = *modeIt; const bool isSeamlessSwitch = mode->getGroup() == mActiveModeIt->second->getGroup(); Loading Loading @@ -451,18 +427,91 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire continue; } const auto layerScore = const float layerScore = calculateLayerScoreLocked(layer, mode->getFps(), isSeamlessSwitch); const float weightedLayerScore = weight * layerScore; // Layer with fixed source has a special consideration 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 layerAboveThreshold = mConfig.frameRateMultipleThreshold != 0 && mode->getFps() >= Fps::fromValue(mConfig.frameRateMultipleThreshold) && layer.desiredRefreshRate < Fps::fromValue(mConfig.frameRateMultipleThreshold / 2); if (fixedSourceLayer) { if (layerAboveThreshold) { ALOGV("%s gives %s fixed source (above threshold) score of %.4f", formatLayerInfo(layer, weight).c_str(), to_string(mode->getFps()).c_str(), layerScore); fixedRateScore.aboveThreshold += 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); fixedRateScore.belowThreshold += weightedLayerScore; } } else { ALOGV("%s gives %s score of %.4f", formatLayerInfo(layer, weight).c_str(), to_string(mode->getFps()).c_str(), layerScore); overallScore += weightedLayerScore; } } } score += weight * layerScore; // We want to find the best refresh rate without the fixed source layers, // so we could know whether we should add the aboveThreshold 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); }(); // Now we can add the fixed rate layers score for (auto& [modeIt, overallScore, fixedRateScore] : scores) { overallScore += fixedRateScore.belowThreshold; if (maxScoreAboveThreshold) { overallScore += fixedRateScore.aboveThreshold; } 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()); Loading @@ -471,7 +520,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}; Loading Loading @@ -575,7 +624,7 @@ RefreshRateConfigs::UidToFrameRateOverride RefreshRateConfigs::getFrameRateOverr continue; } for (auto& [_, score] : scores) { for (auto& [_, score, _1] : scores) { score = 0; } Loading @@ -587,7 +636,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); Loading @@ -605,7 +654,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; } Loading
services/surfaceflinger/Scheduler/RefreshRateConfigs.h +0 −3 Original line number Diff line number Diff line Loading @@ -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, Loading
services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +23 −0 Original line number Diff line number Diff line Loading @@ -639,6 +639,29 @@ 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)); } TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60) { Loading