From 7e796bc1f827bf02adffdb4df06833e64915757e Mon Sep 17 00:00:00 2001 From: Rachel Lee Date: Tue, 5 Nov 2024 10:58:48 -0800 Subject: Toolkit touch boost to per-uid in sf scheduler Fix where the toolkit touchboost ("HighHint" category) is ignored by ExplicitDefault frameRate# vote **only** if it has the same UID (app). - App that setFrameRate(#, default compatibility) still disables touch boost - Fixes cases such as game with setFrameRate(#, default) but HighHint touch on other app e.g. notification shade. The HighHint touch on notification shade should boost, while the game has frame rate override. Bug: 372531483 Flag: EXEMPT bugfix Test: Manual with game 30 Default and notification shade Test: atest libsurfaceflinger_unittest Change-Id: I4c85abe1aad053c3692ffad3e571d8a74ee02227 --- .../Scheduler/RefreshRateSelector.cpp | 120 ++++++++++++--------- .../tests/unittests/RefreshRateSelectorTest.cpp | 85 +++++++++++++++ 2 files changed, 155 insertions(+), 50 deletions(-) diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp index eca8df27d6..68e34d2bfd 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp @@ -489,6 +489,20 @@ auto RefreshRateSelector::getRankedFrameRates(const std::vectorresult; } +using LayerRequirementPtrs = std::vector; +using PerUidLayerRequirements = std::unordered_map; + +PerUidLayerRequirements groupLayersByUid( + const std::vector& layers) { + PerUidLayerRequirements layersByUid; + for (const auto& layer : layers) { + const auto it = layersByUid.emplace(layer.ownerUid, LayerRequirementPtrs()).first; + auto& layersWithSameUid = it->second; + layersWithSameUid.push_back(&layer); + } + return layersByUid; +} + auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector& layers, GlobalSignals signals, Fps pacesetterFps) const -> RankedFrameRates { @@ -525,6 +539,43 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vectorvote) { + case LayerVoteType::ExplicitDefault: + hasExplicitDefault = true; + break; + case LayerVoteType::ExplicitCategory: + if (layer->frameRateCategory == FrameRateCategory::HighHint) { + hasHighHint = true; + } + break; + default: + // No action + break; + } + if (hasHighHint && hasExplicitDefault) { + break; + } + } + + if (hasHighHint && !hasExplicitDefault) { + // Focused app has touch signal (HighHint) and no frame rate ExplicitDefault votes + // (which prevents touch boost due to games use case). + isAppTouchBoost = true; + break; + } + } + int noVoteLayers = 0; // Layers that prefer the same mode ("no-op"). int noPreferenceLayers = 0; @@ -535,7 +586,6 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector 0; - - if (hasInteraction && explicitDefaultVoteLayers == 0 && isTouchBoostForExplicitExact() && - isTouchBoostForCategory()) { + const bool isLateGlobalTouchBoost = signals.touch && explicitDefaultVoteLayers == 0; + const bool isLateTouchBoost = isLateGlobalTouchBoost || isAppTouchBoost; + if (isLateTouchBoost && isTouchBoostForExplicitExact() && isTouchBoostForCategory()) { const auto touchRefreshRates = rankFrameRates(anchorGroup, RefreshRateOrder::Descending); using fps_approx_ops::operator<; @@ -917,42 +962,6 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector; -using PerUidLayerRequirements = std::unordered_map; - -PerUidLayerRequirements groupLayersByUid( - const std::vector& layers) { - PerUidLayerRequirements layersByUid; - for (const auto& layer : layers) { - const auto it = layersByUid.emplace(layer.ownerUid, LayerRequirementPtrs()).first; - auto& layersWithSameUid = it->second; - layersWithSameUid.push_back(&layer); - } - - // Remove uids that can't have a frame rate override - for (auto it = layersByUid.begin(); it != layersByUid.end();) { - const auto& layersWithSameUid = it->second; - bool skipUid = false; - for (const auto& layer : layersWithSameUid) { - using LayerVoteType = RefreshRateSelector::LayerVoteType; - - if (layer->vote == LayerVoteType::Max || layer->vote == LayerVoteType::Heuristic) { - ALOGV("%s: %s skips uid=%d due to the vote", __func__, - formatLayerInfo(*layer, layer->weight).c_str(), layer->ownerUid); - skipUid = true; - break; - } - } - if (skipUid) { - it = layersByUid.erase(it); - } else { - ++it; - } - } - - return layersByUid; -} - auto RefreshRateSelector::getFrameRateOverrides(const std::vector& layers, Fps displayRefreshRate, GlobalSignals globalSignals) const @@ -997,6 +1006,7 @@ auto RefreshRateSelector::getFrameRateOverrides(const std::vectorvote) { case LayerVoteType::ExplicitExactOrMultiple: @@ -1010,15 +1020,25 @@ auto RefreshRateSelector::getFrameRateOverrides(const std::vector layers = {{.ownerUid = 1234, .weight = 1.f}, + {.ownerUid = 5678, .weight = 1.f}}; + auto& lr1 = layers[0]; + auto& lr2 = layers[1]; + + lr1.vote = LayerVoteType::ExplicitCategory; + lr1.frameRateCategory = FrameRateCategory::Normal; + lr1.name = "ExplicitCategory Normal"; + lr2.vote = LayerVoteType::ExplicitDefault; + lr2.desiredRefreshRate = 30_Hz; + lr2.name = "30Hz ExplicitDefault"; + auto actualRankedFrameRates = selector.getRankedFrameRates(layers, {.touch = true}); + // No global touch boost, for example a game that uses setFrameRate(30, default compatibility). + // However see 60 due to Normal vote. + EXPECT_FRAME_RATE_MODE(kVrrMode120TE240, 60_Hz, + actualRankedFrameRates.ranking.front().frameRateMode); + EXPECT_FALSE(actualRankedFrameRates.consideredSignals.touch); + + lr1.vote = LayerVoteType::ExplicitCategory; + lr1.frameRateCategory = FrameRateCategory::HighHint; + lr1.name = "ExplicitCategory HighHint"; + lr2.vote = LayerVoteType::ExplicitDefault; + lr2.desiredRefreshRate = 30_Hz; + lr2.name = "30Hz ExplicitDefault"; + // Gets touch boost because the touched (HighHint) app is different from the 30 Default app. + actualRankedFrameRates = selector.getRankedFrameRates(layers, {.touch = true}); + EXPECT_FRAME_RATE_MODE(kVrrMode120TE240, 120_Hz, + actualRankedFrameRates.ranking.front().frameRateMode); + EXPECT_TRUE(actualRankedFrameRates.consideredSignals.touch); +} + TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_idleTimer_60_120_nonVrr) { SET_FLAG_FOR_TEST(flags::vrr_config, false); @@ -3825,6 +3865,51 @@ TEST_P(RefreshRateSelectorTest, getFrameRateOverrides_twoUids) { EXPECT_TRUE(frameRateOverrides.empty()); } +TEST_P(RefreshRateSelectorTest, getFrameRateOverrides_twoUids_arr) { + if (GetParam() != Config::FrameRateOverride::Enabled) { + return; + } + + SET_FLAG_FOR_TEST(flags::vrr_config, true); + // Device with VRR config mode + auto selector = createSelector(kVrrMode_120, kModeId120); + + std::vector layers = {{.ownerUid = 1234, .weight = 1.f}, + {.ownerUid = 5678, .weight = 1.f}}; + auto& lr1 = layers[0]; + auto& lr2 = layers[1]; + + lr1.vote = LayerVoteType::ExplicitCategory; + lr1.frameRateCategory = FrameRateCategory::Normal; + lr1.name = "ExplicitCategory Normal"; + lr2.vote = LayerVoteType::ExplicitDefault; + lr2.desiredRefreshRate = 30_Hz; + lr2.name = "30Hz ExplicitDefault"; + // No global touch boost, for example a game that uses setFrameRate(30, default compatibility). + // The `displayFrameRate` is 60. + // However 30 Default app still gets frame rate override. + auto frameRateOverrides = selector.getFrameRateOverrides(layers, 60_Hz, {}); + EXPECT_EQ(2u, frameRateOverrides.size()); + ASSERT_EQ(1u, frameRateOverrides.count(1234)); + EXPECT_EQ(60_Hz, frameRateOverrides.at(1234)); + ASSERT_EQ(1u, frameRateOverrides.count(5678)); + EXPECT_EQ(30_Hz, frameRateOverrides.at(5678)); + + lr1.vote = LayerVoteType::ExplicitCategory; + lr1.frameRateCategory = FrameRateCategory::HighHint; + lr1.name = "ExplicitCategory HighHint"; + lr2.vote = LayerVoteType::ExplicitDefault; + lr2.desiredRefreshRate = 30_Hz; + lr2.name = "30Hz ExplicitDefault"; + // Gets touch boost because the touched (HighHint) app is different from the 30 Default app. + // The `displayFrameRate` is 120 (late touch boost). + // However 30 Default app still gets frame rate override. + frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {}); + EXPECT_EQ(1u, frameRateOverrides.size()); + ASSERT_EQ(1u, frameRateOverrides.count(5678)); + EXPECT_EQ(30_Hz, frameRateOverrides.at(5678)); +} + TEST_P(RefreshRateSelectorTest, getFrameRateOverrides_withFrameRateCategory) { if (GetParam() == Config::FrameRateOverride::Disabled) { return; -- cgit v1.2.3-59-g8ed1b