diff options
author | Ady Abraham <adyabr@google.com> | 2021-09-16 15:58:52 -0700 |
---|---|---|
committer | Ady Abraham <adyabr@google.com> | 2022-01-18 18:41:22 -0800 |
commit | b351245a4d39de4d0cb02dd21f1ccaf4773eeb93 (patch) | |
tree | 0793177c504c5a9343c4ebff500fc4280543d341 | |
parent | e3e68adf683d76a83197ac921b7c2b3632117880 (diff) | |
download | native-b351245a4d39de4d0cb02dd21f1ccaf4773eeb93.tar.gz |
SF: give a higher score to frame rates which exact matches
To avoid cases where devices with very close refresh rates
(such as 53Hz and 55Hz) gives the same score for these,
assign a small (0.99) factor to frame rate that are
not exact match of a multiple of the refresh rate
Test: atest FrameRateCtsActivity
Test: atest RefreshRateConfigsTest
Bug: 190578904
Change-Id: Idd32600ccacc0cad8f44c9d9373e50a333663717
Merged-In: Idd32600ccacc0cad8f44c9d9373e50a333663717
3 files changed, 80 insertions, 24 deletions
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index 74ffc8fb9c..661b6c8d43 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -134,27 +134,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) { @@ -179,7 +162,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 @@ -189,7 +172,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) { @@ -207,7 +190,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) { @@ -222,7 +227,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 { diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index 49da973c24..99f217c2e2 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -450,6 +450,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); void initializeIdleTimer(); diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index 9d63d995d9..d8c9babac3 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -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()); }; @@ -2170,6 +2169,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); |