diff options
6 files changed, 109 insertions, 7 deletions
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index a98ea86073..969a5cff05 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -1095,10 +1095,19 @@ enum { ANATIVEWINDOW_FRAME_RATE_CATEGORY_NORMAL = 3, /** + * Indicates that, as a result of a user interaction, an animation is likely to start. + * This category is a signal that a user interaction heuristic determined the need of a + * high refresh rate, and is not an explicit request from the app. + * As opposed to FRAME_RATE_CATEGORY_HIGH, this vote may be ignored in favor of + * more explicit votes. + */ + ANATIVEWINDOW_FRAME_RATE_CATEGORY_HIGH_HINT = 4, + + /** * Indicates a frame rate suitable for animations that require a high frame rate, which may * increase smoothness but may also increase power usage. */ - ANATIVEWINDOW_FRAME_RATE_CATEGORY_HIGH = 4 + ANATIVEWINDOW_FRAME_RATE_CATEGORY_HIGH = 5 }; /* diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp index 97fca395b4..5094232a4e 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.cpp +++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp @@ -528,6 +528,8 @@ FrameRateCategory LayerInfo::FrameRate::convertCategory(int8_t category) { return FrameRateCategory::Low; case ANATIVEWINDOW_FRAME_RATE_CATEGORY_NORMAL: return FrameRateCategory::Normal; + case ANATIVEWINDOW_FRAME_RATE_CATEGORY_HIGH_HINT: + return FrameRateCategory::HighHint; case ANATIVEWINDOW_FRAME_RATE_CATEGORY_HIGH: return FrameRateCategory::High; default: diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp index e06221a43d..c3709e5cc2 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp @@ -420,6 +420,11 @@ float RefreshRateSelector::calculateLayerScoreLocked(const LayerRequirement& lay const float seamlessness = isSeamlessSwitch ? 1.0f : kSeamedSwitchPenalty; if (layer.vote == LayerVoteType::ExplicitCategory) { + // HighHint is considered later for touch boost. + if (layer.frameRateCategory == FrameRateCategory::HighHint) { + return 0.f; + } + if (getFrameRateCategoryRange(layer.frameRateCategory).includes(refreshRate)) { return 1.f; } @@ -507,6 +512,7 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi int explicitExact = 0; int explicitGteLayers = 0; int explicitCategoryVoteLayers = 0; + int interactiveLayers = 0; int seamedFocusedLayers = 0; int categorySmoothSwitchOnlyLayers = 0; @@ -534,7 +540,13 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi explicitGteLayers++; break; case LayerVoteType::ExplicitCategory: - explicitCategoryVoteLayers++; + if (layer.frameRateCategory == FrameRateCategory::HighHint) { + // HighHint does not count as an explicit signal from an app. It may be + // be a touch signal. + interactiveLayers++; + } else { + explicitCategoryVoteLayers++; + } if (layer.frameRateCategory == FrameRateCategory::NoPreference) { // Count this layer for Min vote as well. The explicit vote avoids // touch boost and idle for choosing a category, while Min vote is for correct @@ -831,13 +843,14 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi const auto touchRefreshRates = rankFrameRates(anchorGroup, RefreshRateOrder::Descending); using fps_approx_ops::operator<; - if (signals.touch && explicitDefaultVoteLayers == 0 && explicitCategoryVoteLayers == 0 && + const bool hasInteraction = signals.touch || interactiveLayers > 0; + if (hasInteraction && explicitDefaultVoteLayers == 0 && explicitCategoryVoteLayers == 0 && touchBoostForExplicitExact && scores.front().frameRateMode.fps < touchRefreshRates.front().frameRateMode.fps) { ALOGV("Touch Boost"); ATRACE_FORMAT_INSTANT("%s (Touch Boost [late])", to_string(touchRefreshRates.front().frameRateMode.fps).c_str()); - return {touchRefreshRates, GlobalSignals{.touch = true}}; + return {touchRefreshRates, GlobalSignals{.touch = signals.touch}}; } // If we never scored any layers, and we don't favor high refresh rates, prefer to stay with the @@ -1512,6 +1525,7 @@ FpsRange RefreshRateSelector::getFrameRateCategoryRange(FrameRateCategory catego return FpsRange{60_Hz, 90_Hz}; case FrameRateCategory::Low: return FpsRange{30_Hz, 30_Hz}; + case FrameRateCategory::HighHint: case FrameRateCategory::NoPreference: case FrameRateCategory::Default: LOG_ALWAYS_FATAL("Should not get fps range for frame rate category: %s", diff --git a/services/surfaceflinger/Scheduler/include/scheduler/Fps.h b/services/surfaceflinger/Scheduler/include/scheduler/Fps.h index 2806450c5f..84ef89fb4a 100644 --- a/services/surfaceflinger/Scheduler/include/scheduler/Fps.h +++ b/services/surfaceflinger/Scheduler/include/scheduler/Fps.h @@ -88,6 +88,7 @@ enum class FrameRateCategory : int32_t { NoPreference, Low, Normal, + HighHint, High, ftl_last = High diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp index ba32c68b61..55b20b3b47 100644 --- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp @@ -650,7 +650,7 @@ TEST_F(LayerSnapshotTest, frameRateWithCategory) { // │ └── 13 // └── 2 setFrameRate(11, 244.f, 0, 0); - setFrameRateCategory(122, 3 /* Normal */); + setFrameRateCategory(122, ANATIVEWINDOW_FRAME_RATE_CATEGORY_NORMAL); UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); // verify parent 1 gets no vote @@ -845,7 +845,7 @@ TEST_F(LayerSnapshotTest, frameRateSelectionStrategyWithCategory) { // │ │ └── 1221 // │ └── 13 // └── 2 - setFrameRateCategory(12, 4 /* high */); + setFrameRateCategory(12, ANATIVEWINDOW_FRAME_RATE_CATEGORY_HIGH); setFrameRate(122, 123.f, 0, 0); setFrameRateSelectionStrategy(12, 1 /* OverrideChildren */); @@ -887,7 +887,7 @@ TEST_F(LayerSnapshotTest, frameRateSelectionStrategyWithCategory) { // │ │ └── 1221 // │ └── 13 // └── 2 - setFrameRateCategory(12, 0 /* default */); + setFrameRateCategory(12, ANATIVEWINDOW_FRAME_RATE_CATEGORY_DEFAULT); setFrameRateSelectionStrategy(12, 0 /* Default */); UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); // verify parent 1 gets no vote diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp index 0cacf810c0..1e526ba348 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp @@ -1607,6 +1607,82 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_60_12 } } +TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_HighHint) { + auto selector = createSelector(makeModes(kMode24, kMode30, kMode60, kMode120), kModeId60); + + std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}}; + auto& lr1 = layers[0]; + auto& lr2 = layers[1]; + + lr1.vote = LayerVoteType::ExplicitCategory; + lr1.frameRateCategory = FrameRateCategory::HighHint; + lr1.name = "ExplicitCategory HighHint"; + lr2.vote = LayerVoteType::NoVote; + lr2.name = "NoVote"; + auto actualFrameRateMode = selector.getBestFrameRateMode(layers); + // Gets touch boost + EXPECT_EQ(120_Hz, actualFrameRateMode.fps); + EXPECT_EQ(kModeId120, actualFrameRateMode.modePtr->getId()); + + lr1.vote = LayerVoteType::ExplicitCategory; + lr1.frameRateCategory = FrameRateCategory::HighHint; + lr1.name = "ExplicitCategory HighHint"; + lr2.vote = LayerVoteType::ExplicitDefault; + lr2.desiredRefreshRate = 30_Hz; + lr2.name = "30Hz ExplicitDefault"; + actualFrameRateMode = selector.getBestFrameRateMode(layers); + EXPECT_EQ(30_Hz, actualFrameRateMode.fps); + EXPECT_EQ(kModeId30, actualFrameRateMode.modePtr->getId()); + + lr1.vote = LayerVoteType::ExplicitCategory; + lr1.frameRateCategory = FrameRateCategory::HighHint; + lr1.name = "ExplicitCategory HighHint"; + lr2.vote = LayerVoteType::ExplicitCategory; + lr2.frameRateCategory = FrameRateCategory::HighHint; + lr2.name = "ExplicitCategory HighHint#2"; + actualFrameRateMode = selector.getBestFrameRateMode(layers); + // Gets touch boost + EXPECT_EQ(120_Hz, actualFrameRateMode.fps); + EXPECT_EQ(kModeId120, actualFrameRateMode.modePtr->getId()); + + lr1.vote = LayerVoteType::ExplicitCategory; + lr1.frameRateCategory = FrameRateCategory::HighHint; + lr1.name = "ExplicitCategory HighHint"; + lr2.vote = LayerVoteType::ExplicitCategory; + lr2.frameRateCategory = FrameRateCategory::Low; + lr2.name = "ExplicitCategory Low"; + actualFrameRateMode = selector.getBestFrameRateMode(layers); + EXPECT_EQ(30_Hz, actualFrameRateMode.fps); + EXPECT_EQ(kModeId30, actualFrameRateMode.modePtr->getId()); + + lr1.vote = LayerVoteType::ExplicitCategory; + lr1.frameRateCategory = FrameRateCategory::HighHint; + lr1.name = "ExplicitCategory HighHint"; + lr2.vote = LayerVoteType::ExplicitExactOrMultiple; + lr2.desiredRefreshRate = 30_Hz; + lr2.name = "30Hz ExplicitExactOrMultiple"; + actualFrameRateMode = selector.getBestFrameRateMode(layers); + // Gets touch boost + EXPECT_EQ(120_Hz, actualFrameRateMode.fps); + EXPECT_EQ(kModeId120, actualFrameRateMode.modePtr->getId()); + + lr1.vote = LayerVoteType::ExplicitCategory; + lr1.frameRateCategory = FrameRateCategory::HighHint; + lr1.name = "ExplicitCategory HighHint"; + lr2.vote = LayerVoteType::ExplicitExact; + lr2.desiredRefreshRate = 30_Hz; + lr2.name = "30Hz ExplicitExact"; + actualFrameRateMode = selector.getBestFrameRateMode(layers); + if (selector.supportsAppFrameRateOverrideByContent()) { + // Gets touch boost + EXPECT_EQ(120_Hz, actualFrameRateMode.fps); + EXPECT_EQ(kModeId120, actualFrameRateMode.modePtr->getId()); + } else { + EXPECT_EQ(30_Hz, actualFrameRateMode.fps); + EXPECT_EQ(kModeId30, actualFrameRateMode.modePtr->getId()); + } +} + TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_smoothSwitchOnly_60_120_nonVrr) { if (GetParam() != Config::FrameRateOverride::Enabled) { |