Loading services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +39 −23 Original line number Diff line number Diff line Loading @@ -133,27 +133,10 @@ bool RefreshRateConfigs::isVoteAllowed(const LayerRequirement& layer, return true; } float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& layer, const RefreshRate& refreshRate, bool isSeamlessSwitch) const { if (!isVoteAllowed(layer, refreshRate)) { return 0; } float RefreshRateConfigs::calculateNonExactMatchingLayerScoreLocked( const LayerRequirement& layer, const RefreshRate& refreshRate) const { constexpr float kScoreForFractionalPairs = .8f; // Slightly prefer seamless switches. constexpr float kSeamedSwitchPenalty = 0.95f; const float seamlessness = isSeamlessSwitch ? 1.0f : kSeamedSwitchPenalty; // If the layer wants Max, give higher score to the higher refresh rate if (layer.vote == LayerVoteType::Max) { const auto ratio = refreshRate.getFps().getValue() / mAppRequestRefreshRates.back()->getFps().getValue(); // use ratio^2 to get a lower score the more we get further from peak return ratio * ratio; } const auto displayPeriod = refreshRate.getVsyncPeriod(); const auto layerPeriod = layer.desiredRefreshRate.getPeriodNsecs(); if (layer.vote == LayerVoteType::ExplicitDefault) { Loading @@ -178,7 +161,7 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye if (layer.vote == LayerVoteType::ExplicitExactOrMultiple || layer.vote == LayerVoteType::Heuristic) { if (isFractionalPairOrMultiple(refreshRate.getFps(), layer.desiredRefreshRate)) { return kScoreForFractionalPairs * seamlessness; return kScoreForFractionalPairs; } // Calculate how many display vsyncs we need to present a single frame for this Loading @@ -188,7 +171,7 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye static constexpr size_t MAX_FRAMES_TO_FIT = 10; // Stop calculating when score < 0.1 if (displayFramesRemainder == 0) { // Layer desired refresh rate matches the display rate. return 1.0f * seamlessness; return 1.0f; } if (displayFramesQuotient == 0) { Loading @@ -206,7 +189,29 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye iter++; } return (1.0f / iter) * seamlessness; return (1.0f / iter); } return 0; } float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& layer, const RefreshRate& 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; // If the layer wants Max, give higher score to the higher refresh rate if (layer.vote == LayerVoteType::Max) { const auto ratio = refreshRate.getFps().getValue() / mAppRequestRefreshRates.back()->getFps().getValue(); // use ratio^2 to get a lower score the more we get further from peak return ratio * ratio; } if (layer.vote == LayerVoteType::ExplicitExact) { Loading @@ -221,7 +226,18 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye return divider == 1; } return 0; // If the layer frame rate is a divider of the refresh rate it should score // the highest score. if (getFrameRateDivider(refreshRate.getFps(), layer.desiredRefreshRate) > 0) { return 1.0f * seamlessness; } // The layer frame rate is not a divider of the refresh rate, // there is a small penalty attached to the score to favor the frame rates // the exactly matches the display refresh rate or a multiple. constexpr float kNonExactMatchingPenalty = 0.99f; return calculateNonExactMatchingLayerScoreLocked(layer, refreshRate) * seamlessness * kNonExactMatchingPenalty; } struct RefreshRateScore { Loading services/surfaceflinger/Scheduler/RefreshRateConfigs.h +3 −0 Original line number Diff line number Diff line Loading @@ -409,6 +409,9 @@ private: float calculateLayerScoreLocked(const LayerRequirement&, const RefreshRate&, bool isSeamlessSwitch) const REQUIRES(mLock); float calculateNonExactMatchingLayerScoreLocked(const LayerRequirement&, const RefreshRate&) const REQUIRES(mLock); void updateDisplayModes(const DisplayModes& mode, DisplayModeId currentModeId) EXCLUDES(mLock); // The list of refresh rates, indexed by display modes ID. This may change after this Loading services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +38 −1 Original line number Diff line number Diff line Loading @@ -175,7 +175,6 @@ protected: RefreshRate mExpected30Config = {mConfig30, RefreshRate::ConstructorTag(0)}; RefreshRate mExpected120Config = {mConfig120, RefreshRate::ConstructorTag(0)}; private: DisplayModePtr createDisplayMode(DisplayModeId modeId, int32_t group, int64_t vsyncPeriod, ui::Size resolution = ui::Size()); }; Loading Loading @@ -2179,6 +2178,44 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_FractionalRefreshRates_ExactAn refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); } // b/190578904 TEST_F(RefreshRateConfigsTest, getBestRefreshRate_deviceWithCloseRefreshRates) { constexpr int kMinRefreshRate = 10; constexpr int kMaxRefreshRate = 240; DisplayModes displayModes; for (int fps = kMinRefreshRate; fps < kMaxRefreshRate; fps++) { constexpr int32_t kGroup = 0; const auto refreshRate = Fps(static_cast<float>(fps)); displayModes.push_back( createDisplayMode(DisplayModeId(fps), kGroup, refreshRate.getPeriodNsecs())); } const RefreshRateConfigs::GlobalSignals globalSignals = {.touch = false, .idle = false}; auto refreshRateConfigs = std::make_unique<RefreshRateConfigs>(displayModes, /*currentConfigId=*/displayModes[0]->getId()); auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}}; const auto testRefreshRate = [&](Fps fps, LayerVoteType vote) { layers[0].desiredRefreshRate = fps; layers[0].vote = vote; EXPECT_EQ(fps.getIntValue(), refreshRateConfigs->getBestRefreshRate(layers, globalSignals) .getFps() .getIntValue()) << "Failed for " << RefreshRateConfigs::layerVoteTypeString(vote); }; for (int fps = kMinRefreshRate; fps < kMaxRefreshRate; fps++) { const auto refreshRate = Fps(static_cast<float>(fps)); testRefreshRate(refreshRate, LayerVoteType::Heuristic); testRefreshRate(refreshRate, LayerVoteType::ExplicitDefault); testRefreshRate(refreshRate, LayerVoteType::ExplicitExactOrMultiple); testRefreshRate(refreshRate, LayerVoteType::ExplicitExact); } } TEST_F(RefreshRateConfigsTest, testComparisonOperator) { EXPECT_TRUE(mExpected60Config < mExpected90Config); EXPECT_FALSE(mExpected60Config < mExpected60Config); Loading Loading
services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +39 −23 Original line number Diff line number Diff line Loading @@ -133,27 +133,10 @@ bool RefreshRateConfigs::isVoteAllowed(const LayerRequirement& layer, return true; } float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& layer, const RefreshRate& refreshRate, bool isSeamlessSwitch) const { if (!isVoteAllowed(layer, refreshRate)) { return 0; } float RefreshRateConfigs::calculateNonExactMatchingLayerScoreLocked( const LayerRequirement& layer, const RefreshRate& refreshRate) const { constexpr float kScoreForFractionalPairs = .8f; // Slightly prefer seamless switches. constexpr float kSeamedSwitchPenalty = 0.95f; const float seamlessness = isSeamlessSwitch ? 1.0f : kSeamedSwitchPenalty; // If the layer wants Max, give higher score to the higher refresh rate if (layer.vote == LayerVoteType::Max) { const auto ratio = refreshRate.getFps().getValue() / mAppRequestRefreshRates.back()->getFps().getValue(); // use ratio^2 to get a lower score the more we get further from peak return ratio * ratio; } const auto displayPeriod = refreshRate.getVsyncPeriod(); const auto layerPeriod = layer.desiredRefreshRate.getPeriodNsecs(); if (layer.vote == LayerVoteType::ExplicitDefault) { Loading @@ -178,7 +161,7 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye if (layer.vote == LayerVoteType::ExplicitExactOrMultiple || layer.vote == LayerVoteType::Heuristic) { if (isFractionalPairOrMultiple(refreshRate.getFps(), layer.desiredRefreshRate)) { return kScoreForFractionalPairs * seamlessness; return kScoreForFractionalPairs; } // Calculate how many display vsyncs we need to present a single frame for this Loading @@ -188,7 +171,7 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye static constexpr size_t MAX_FRAMES_TO_FIT = 10; // Stop calculating when score < 0.1 if (displayFramesRemainder == 0) { // Layer desired refresh rate matches the display rate. return 1.0f * seamlessness; return 1.0f; } if (displayFramesQuotient == 0) { Loading @@ -206,7 +189,29 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye iter++; } return (1.0f / iter) * seamlessness; return (1.0f / iter); } return 0; } float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& layer, const RefreshRate& 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; // If the layer wants Max, give higher score to the higher refresh rate if (layer.vote == LayerVoteType::Max) { const auto ratio = refreshRate.getFps().getValue() / mAppRequestRefreshRates.back()->getFps().getValue(); // use ratio^2 to get a lower score the more we get further from peak return ratio * ratio; } if (layer.vote == LayerVoteType::ExplicitExact) { Loading @@ -221,7 +226,18 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye return divider == 1; } return 0; // If the layer frame rate is a divider of the refresh rate it should score // the highest score. if (getFrameRateDivider(refreshRate.getFps(), layer.desiredRefreshRate) > 0) { return 1.0f * seamlessness; } // The layer frame rate is not a divider of the refresh rate, // there is a small penalty attached to the score to favor the frame rates // the exactly matches the display refresh rate or a multiple. constexpr float kNonExactMatchingPenalty = 0.99f; return calculateNonExactMatchingLayerScoreLocked(layer, refreshRate) * seamlessness * kNonExactMatchingPenalty; } struct RefreshRateScore { Loading
services/surfaceflinger/Scheduler/RefreshRateConfigs.h +3 −0 Original line number Diff line number Diff line Loading @@ -409,6 +409,9 @@ private: float calculateLayerScoreLocked(const LayerRequirement&, const RefreshRate&, bool isSeamlessSwitch) const REQUIRES(mLock); float calculateNonExactMatchingLayerScoreLocked(const LayerRequirement&, const RefreshRate&) const REQUIRES(mLock); void updateDisplayModes(const DisplayModes& mode, DisplayModeId currentModeId) EXCLUDES(mLock); // The list of refresh rates, indexed by display modes ID. This may change after this Loading
services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +38 −1 Original line number Diff line number Diff line Loading @@ -175,7 +175,6 @@ protected: RefreshRate mExpected30Config = {mConfig30, RefreshRate::ConstructorTag(0)}; RefreshRate mExpected120Config = {mConfig120, RefreshRate::ConstructorTag(0)}; private: DisplayModePtr createDisplayMode(DisplayModeId modeId, int32_t group, int64_t vsyncPeriod, ui::Size resolution = ui::Size()); }; Loading Loading @@ -2179,6 +2178,44 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_FractionalRefreshRates_ExactAn refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); } // b/190578904 TEST_F(RefreshRateConfigsTest, getBestRefreshRate_deviceWithCloseRefreshRates) { constexpr int kMinRefreshRate = 10; constexpr int kMaxRefreshRate = 240; DisplayModes displayModes; for (int fps = kMinRefreshRate; fps < kMaxRefreshRate; fps++) { constexpr int32_t kGroup = 0; const auto refreshRate = Fps(static_cast<float>(fps)); displayModes.push_back( createDisplayMode(DisplayModeId(fps), kGroup, refreshRate.getPeriodNsecs())); } const RefreshRateConfigs::GlobalSignals globalSignals = {.touch = false, .idle = false}; auto refreshRateConfigs = std::make_unique<RefreshRateConfigs>(displayModes, /*currentConfigId=*/displayModes[0]->getId()); auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}}; const auto testRefreshRate = [&](Fps fps, LayerVoteType vote) { layers[0].desiredRefreshRate = fps; layers[0].vote = vote; EXPECT_EQ(fps.getIntValue(), refreshRateConfigs->getBestRefreshRate(layers, globalSignals) .getFps() .getIntValue()) << "Failed for " << RefreshRateConfigs::layerVoteTypeString(vote); }; for (int fps = kMinRefreshRate; fps < kMaxRefreshRate; fps++) { const auto refreshRate = Fps(static_cast<float>(fps)); testRefreshRate(refreshRate, LayerVoteType::Heuristic); testRefreshRate(refreshRate, LayerVoteType::ExplicitDefault); testRefreshRate(refreshRate, LayerVoteType::ExplicitExactOrMultiple); testRefreshRate(refreshRate, LayerVoteType::ExplicitExact); } } TEST_F(RefreshRateConfigsTest, testComparisonOperator) { EXPECT_TRUE(mExpected60Config < mExpected90Config); EXPECT_FALSE(mExpected60Config < mExpected60Config); Loading