Skip to content

Commit 6bc812d

Browse files
Treehugger RobotAndroid (Google) Code Review
authored andcommitted
Merge "Toolkit touch boost to per-uid in sf scheduler" into main
2 parents b8591fb + 7e796bc commit 6bc812d

2 files changed

Lines changed: 155 additions & 50 deletions

File tree

services/surfaceflinger/Scheduler/RefreshRateSelector.cpp

Lines changed: 70 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,20 @@ auto RefreshRateSelector::getRankedFrameRates(const std::vector<LayerRequirement
489489
return mGetRankedFrameRatesCache->result;
490490
}
491491

492+
using LayerRequirementPtrs = std::vector<const RefreshRateSelector::LayerRequirement*>;
493+
using PerUidLayerRequirements = std::unordered_map<uid_t, LayerRequirementPtrs>;
494+
495+
PerUidLayerRequirements groupLayersByUid(
496+
const std::vector<RefreshRateSelector::LayerRequirement>& layers) {
497+
PerUidLayerRequirements layersByUid;
498+
for (const auto& layer : layers) {
499+
const auto it = layersByUid.emplace(layer.ownerUid, LayerRequirementPtrs()).first;
500+
auto& layersWithSameUid = it->second;
501+
layersWithSameUid.push_back(&layer);
502+
}
503+
return layersByUid;
504+
}
505+
492506
auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequirement>& layers,
493507
GlobalSignals signals, Fps pacesetterFps) const
494508
-> RankedFrameRates {
@@ -525,6 +539,43 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi
525539
return {ranking, GlobalSignals{.powerOnImminent = true}};
526540
}
527541

542+
// A method for UI Toolkit to send the touch signal via "HighHint" category vote,
543+
// which will touch boost when there are no ExplicitDefault layer votes on the app.
544+
// At most one app can have the "HighHint" touch boost vote at a time.
545+
// This accounts for cases such as games that use `setFrameRate`
546+
// with Default compatibility to limit the frame rate and disabling touch boost.
547+
bool isAppTouchBoost = false;
548+
const auto layersByUid = groupLayersByUid(layers);
549+
for (const auto& [uid, layersWithSameUid] : layersByUid) {
550+
bool hasHighHint = false;
551+
bool hasExplicitDefault = false;
552+
for (const auto& layer : layersWithSameUid) {
553+
switch (layer->vote) {
554+
case LayerVoteType::ExplicitDefault:
555+
hasExplicitDefault = true;
556+
break;
557+
case LayerVoteType::ExplicitCategory:
558+
if (layer->frameRateCategory == FrameRateCategory::HighHint) {
559+
hasHighHint = true;
560+
}
561+
break;
562+
default:
563+
// No action
564+
break;
565+
}
566+
if (hasHighHint && hasExplicitDefault) {
567+
break;
568+
}
569+
}
570+
571+
if (hasHighHint && !hasExplicitDefault) {
572+
// Focused app has touch signal (HighHint) and no frame rate ExplicitDefault votes
573+
// (which prevents touch boost due to games use case).
574+
isAppTouchBoost = true;
575+
break;
576+
}
577+
}
578+
528579
int noVoteLayers = 0;
529580
// Layers that prefer the same mode ("no-op").
530581
int noPreferenceLayers = 0;
@@ -535,7 +586,6 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi
535586
int explicitExact = 0;
536587
int explicitGteLayers = 0;
537588
int explicitCategoryVoteLayers = 0;
538-
int interactiveLayers = 0;
539589
int seamedFocusedLayers = 0;
540590
int categorySmoothSwitchOnlyLayers = 0;
541591

@@ -563,11 +613,9 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi
563613
explicitGteLayers++;
564614
break;
565615
case LayerVoteType::ExplicitCategory:
566-
if (layer.frameRateCategory == FrameRateCategory::HighHint) {
567-
// HighHint does not count as an explicit signal from an app. It may be
568-
// be a touch signal.
569-
interactiveLayers++;
570-
} else {
616+
// HighHint does not count as an explicit signal from an app. It is a touch signal
617+
// sent from UI Toolkit.
618+
if (layer.frameRateCategory != FrameRateCategory::HighHint) {
571619
explicitCategoryVoteLayers++;
572620
}
573621
if (layer.frameRateCategory == FrameRateCategory::NoPreference) {
@@ -882,14 +930,11 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi
882930
return explicitCategoryVoteLayers + noVoteLayers + explicitGteLayers != layers.size();
883931
};
884932

885-
// A method for UI Toolkit to send the touch signal via "HighHint" category vote,
886-
// which will touch boost when there are no ExplicitDefault layer votes. This is an
887-
// incomplete solution but accounts for cases such as games that use `setFrameRate` with default
933+
// This accounts for cases such as games that use `setFrameRate` with Default
888934
// compatibility to limit the frame rate, which should not have touch boost.
889-
const bool hasInteraction = signals.touch || interactiveLayers > 0;
890-
891-
if (hasInteraction && explicitDefaultVoteLayers == 0 && isTouchBoostForExplicitExact() &&
892-
isTouchBoostForCategory()) {
935+
const bool isLateGlobalTouchBoost = signals.touch && explicitDefaultVoteLayers == 0;
936+
const bool isLateTouchBoost = isLateGlobalTouchBoost || isAppTouchBoost;
937+
if (isLateTouchBoost && isTouchBoostForExplicitExact() && isTouchBoostForCategory()) {
893938
const auto touchRefreshRates = rankFrameRates(anchorGroup, RefreshRateOrder::Descending);
894939
using fps_approx_ops::operator<;
895940

@@ -917,42 +962,6 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi
917962
return {ranking, kNoSignals};
918963
}
919964

920-
using LayerRequirementPtrs = std::vector<const RefreshRateSelector::LayerRequirement*>;
921-
using PerUidLayerRequirements = std::unordered_map<uid_t, LayerRequirementPtrs>;
922-
923-
PerUidLayerRequirements groupLayersByUid(
924-
const std::vector<RefreshRateSelector::LayerRequirement>& layers) {
925-
PerUidLayerRequirements layersByUid;
926-
for (const auto& layer : layers) {
927-
const auto it = layersByUid.emplace(layer.ownerUid, LayerRequirementPtrs()).first;
928-
auto& layersWithSameUid = it->second;
929-
layersWithSameUid.push_back(&layer);
930-
}
931-
932-
// Remove uids that can't have a frame rate override
933-
for (auto it = layersByUid.begin(); it != layersByUid.end();) {
934-
const auto& layersWithSameUid = it->second;
935-
bool skipUid = false;
936-
for (const auto& layer : layersWithSameUid) {
937-
using LayerVoteType = RefreshRateSelector::LayerVoteType;
938-
939-
if (layer->vote == LayerVoteType::Max || layer->vote == LayerVoteType::Heuristic) {
940-
ALOGV("%s: %s skips uid=%d due to the vote", __func__,
941-
formatLayerInfo(*layer, layer->weight).c_str(), layer->ownerUid);
942-
skipUid = true;
943-
break;
944-
}
945-
}
946-
if (skipUid) {
947-
it = layersByUid.erase(it);
948-
} else {
949-
++it;
950-
}
951-
}
952-
953-
return layersByUid;
954-
}
955-
956965
auto RefreshRateSelector::getFrameRateOverrides(const std::vector<LayerRequirement>& layers,
957966
Fps displayRefreshRate,
958967
GlobalSignals globalSignals) const
@@ -997,6 +1006,7 @@ auto RefreshRateSelector::getFrameRateOverrides(const std::vector<LayerRequireme
9971006
bool hasExplicitExactOrMultiple = false;
9981007
bool hasExplicitDefault = false;
9991008
bool hasHighHint = false;
1009+
bool hasSkipOverrideLayer = false;
10001010
for (const auto& layer : layersWithSameUid) {
10011011
switch (layer->vote) {
10021012
case LayerVoteType::ExplicitExactOrMultiple:
@@ -1010,15 +1020,25 @@ auto RefreshRateSelector::getFrameRateOverrides(const std::vector<LayerRequireme
10101020
hasHighHint = true;
10111021
}
10121022
break;
1023+
case LayerVoteType::Max:
1024+
case LayerVoteType::Heuristic:
1025+
hasSkipOverrideLayer = true;
1026+
break;
10131027
default:
10141028
// No action
10151029
break;
10161030
}
1017-
if (hasExplicitExactOrMultiple && hasExplicitDefault && hasHighHint) {
1031+
if (hasExplicitExactOrMultiple && hasExplicitDefault && hasHighHint &&
1032+
hasSkipOverrideLayer) {
10181033
break;
10191034
}
10201035
}
10211036

1037+
if (hasSkipOverrideLayer) {
1038+
ALOGV("%s: Skipping due to vote(s): uid=%d", __func__, uid);
1039+
continue;
1040+
}
1041+
10221042
// Layers with ExplicitExactOrMultiple expect touch boost
10231043
if (globalSignals.touch && hasExplicitExactOrMultiple) {
10241044
ALOGV("%s: Skipping for touch (input signal): uid=%d", __func__, uid);

services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2240,6 +2240,46 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_Touch
22402240
EXPECT_FALSE(actualRankedFrameRates.consideredSignals.touch);
22412241
}
22422242

2243+
TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_touchBoost_twoUids_arr) {
2244+
if (GetParam() != Config::FrameRateOverride::Enabled) {
2245+
return;
2246+
}
2247+
2248+
SET_FLAG_FOR_TEST(flags::vrr_config, true);
2249+
// Device with VRR config mode
2250+
auto selector = createSelector(kVrrMode_120, kModeId120);
2251+
2252+
std::vector<LayerRequirement> layers = {{.ownerUid = 1234, .weight = 1.f},
2253+
{.ownerUid = 5678, .weight = 1.f}};
2254+
auto& lr1 = layers[0];
2255+
auto& lr2 = layers[1];
2256+
2257+
lr1.vote = LayerVoteType::ExplicitCategory;
2258+
lr1.frameRateCategory = FrameRateCategory::Normal;
2259+
lr1.name = "ExplicitCategory Normal";
2260+
lr2.vote = LayerVoteType::ExplicitDefault;
2261+
lr2.desiredRefreshRate = 30_Hz;
2262+
lr2.name = "30Hz ExplicitDefault";
2263+
auto actualRankedFrameRates = selector.getRankedFrameRates(layers, {.touch = true});
2264+
// No global touch boost, for example a game that uses setFrameRate(30, default compatibility).
2265+
// However see 60 due to Normal vote.
2266+
EXPECT_FRAME_RATE_MODE(kVrrMode120TE240, 60_Hz,
2267+
actualRankedFrameRates.ranking.front().frameRateMode);
2268+
EXPECT_FALSE(actualRankedFrameRates.consideredSignals.touch);
2269+
2270+
lr1.vote = LayerVoteType::ExplicitCategory;
2271+
lr1.frameRateCategory = FrameRateCategory::HighHint;
2272+
lr1.name = "ExplicitCategory HighHint";
2273+
lr2.vote = LayerVoteType::ExplicitDefault;
2274+
lr2.desiredRefreshRate = 30_Hz;
2275+
lr2.name = "30Hz ExplicitDefault";
2276+
// Gets touch boost because the touched (HighHint) app is different from the 30 Default app.
2277+
actualRankedFrameRates = selector.getRankedFrameRates(layers, {.touch = true});
2278+
EXPECT_FRAME_RATE_MODE(kVrrMode120TE240, 120_Hz,
2279+
actualRankedFrameRates.ranking.front().frameRateMode);
2280+
EXPECT_TRUE(actualRankedFrameRates.consideredSignals.touch);
2281+
}
2282+
22432283
TEST_P(RefreshRateSelectorTest,
22442284
getBestFrameRateMode_withFrameRateCategory_idleTimer_60_120_nonVrr) {
22452285
SET_FLAG_FOR_TEST(flags::vrr_config, false);
@@ -3825,6 +3865,51 @@ TEST_P(RefreshRateSelectorTest, getFrameRateOverrides_twoUids) {
38253865
EXPECT_TRUE(frameRateOverrides.empty());
38263866
}
38273867

3868+
TEST_P(RefreshRateSelectorTest, getFrameRateOverrides_twoUids_arr) {
3869+
if (GetParam() != Config::FrameRateOverride::Enabled) {
3870+
return;
3871+
}
3872+
3873+
SET_FLAG_FOR_TEST(flags::vrr_config, true);
3874+
// Device with VRR config mode
3875+
auto selector = createSelector(kVrrMode_120, kModeId120);
3876+
3877+
std::vector<LayerRequirement> layers = {{.ownerUid = 1234, .weight = 1.f},
3878+
{.ownerUid = 5678, .weight = 1.f}};
3879+
auto& lr1 = layers[0];
3880+
auto& lr2 = layers[1];
3881+
3882+
lr1.vote = LayerVoteType::ExplicitCategory;
3883+
lr1.frameRateCategory = FrameRateCategory::Normal;
3884+
lr1.name = "ExplicitCategory Normal";
3885+
lr2.vote = LayerVoteType::ExplicitDefault;
3886+
lr2.desiredRefreshRate = 30_Hz;
3887+
lr2.name = "30Hz ExplicitDefault";
3888+
// No global touch boost, for example a game that uses setFrameRate(30, default compatibility).
3889+
// The `displayFrameRate` is 60.
3890+
// However 30 Default app still gets frame rate override.
3891+
auto frameRateOverrides = selector.getFrameRateOverrides(layers, 60_Hz, {});
3892+
EXPECT_EQ(2u, frameRateOverrides.size());
3893+
ASSERT_EQ(1u, frameRateOverrides.count(1234));
3894+
EXPECT_EQ(60_Hz, frameRateOverrides.at(1234));
3895+
ASSERT_EQ(1u, frameRateOverrides.count(5678));
3896+
EXPECT_EQ(30_Hz, frameRateOverrides.at(5678));
3897+
3898+
lr1.vote = LayerVoteType::ExplicitCategory;
3899+
lr1.frameRateCategory = FrameRateCategory::HighHint;
3900+
lr1.name = "ExplicitCategory HighHint";
3901+
lr2.vote = LayerVoteType::ExplicitDefault;
3902+
lr2.desiredRefreshRate = 30_Hz;
3903+
lr2.name = "30Hz ExplicitDefault";
3904+
// Gets touch boost because the touched (HighHint) app is different from the 30 Default app.
3905+
// The `displayFrameRate` is 120 (late touch boost).
3906+
// However 30 Default app still gets frame rate override.
3907+
frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {});
3908+
EXPECT_EQ(1u, frameRateOverrides.size());
3909+
ASSERT_EQ(1u, frameRateOverrides.count(5678));
3910+
EXPECT_EQ(30_Hz, frameRateOverrides.at(5678));
3911+
}
3912+
38283913
TEST_P(RefreshRateSelectorTest, getFrameRateOverrides_withFrameRateCategory) {
38293914
if (GetParam() == Config::FrameRateOverride::Disabled) {
38303915
return;

0 commit comments

Comments
 (0)