Loading services/surfaceflinger/Scheduler/RefreshRateSelector.cpp +70 −50 Original line number Diff line number Diff line Loading @@ -489,6 +489,20 @@ auto RefreshRateSelector::getRankedFrameRates(const std::vector<LayerRequirement return mGetRankedFrameRatesCache->result; } using LayerRequirementPtrs = std::vector<const RefreshRateSelector::LayerRequirement*>; using PerUidLayerRequirements = std::unordered_map<uid_t, LayerRequirementPtrs>; PerUidLayerRequirements groupLayersByUid( const std::vector<RefreshRateSelector::LayerRequirement>& 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<LayerRequirement>& layers, GlobalSignals signals, Fps pacesetterFps) const -> RankedFrameRates { Loading Loading @@ -525,6 +539,43 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi return {ranking, GlobalSignals{.powerOnImminent = true}}; } // A method for UI Toolkit to send the touch signal via "HighHint" category vote, // which will touch boost when there are no ExplicitDefault layer votes on the app. // At most one app can have the "HighHint" touch boost vote at a time. // This accounts for cases such as games that use `setFrameRate` // with Default compatibility to limit the frame rate and disabling touch boost. bool isAppTouchBoost = false; const auto layersByUid = groupLayersByUid(layers); for (const auto& [uid, layersWithSameUid] : layersByUid) { bool hasHighHint = false; bool hasExplicitDefault = false; for (const auto& layer : layersWithSameUid) { switch (layer->vote) { 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; Loading @@ -535,7 +586,6 @@ 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; Loading Loading @@ -563,11 +613,9 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi explicitGteLayers++; break; case LayerVoteType::ExplicitCategory: 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 { // HighHint does not count as an explicit signal from an app. It is a touch signal // sent from UI Toolkit. if (layer.frameRateCategory != FrameRateCategory::HighHint) { explicitCategoryVoteLayers++; } if (layer.frameRateCategory == FrameRateCategory::NoPreference) { Loading Loading @@ -882,14 +930,11 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi return explicitCategoryVoteLayers + noVoteLayers + explicitGteLayers != layers.size(); }; // A method for UI Toolkit to send the touch signal via "HighHint" category vote, // which will touch boost when there are no ExplicitDefault layer votes. This is an // incomplete solution but accounts for cases such as games that use `setFrameRate` with default // This accounts for cases such as games that use `setFrameRate` with Default // compatibility to limit the frame rate, which should not have touch boost. const bool hasInteraction = signals.touch || interactiveLayers > 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<; Loading Loading @@ -917,42 +962,6 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi return {ranking, kNoSignals}; } using LayerRequirementPtrs = std::vector<const RefreshRateSelector::LayerRequirement*>; using PerUidLayerRequirements = std::unordered_map<uid_t, LayerRequirementPtrs>; PerUidLayerRequirements groupLayersByUid( const std::vector<RefreshRateSelector::LayerRequirement>& 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<LayerRequirement>& layers, Fps displayRefreshRate, GlobalSignals globalSignals) const Loading Loading @@ -997,6 +1006,7 @@ auto RefreshRateSelector::getFrameRateOverrides(const std::vector<LayerRequireme bool hasExplicitExactOrMultiple = false; bool hasExplicitDefault = false; bool hasHighHint = false; bool hasSkipOverrideLayer = false; for (const auto& layer : layersWithSameUid) { switch (layer->vote) { case LayerVoteType::ExplicitExactOrMultiple: Loading @@ -1010,15 +1020,25 @@ auto RefreshRateSelector::getFrameRateOverrides(const std::vector<LayerRequireme hasHighHint = true; } break; case LayerVoteType::Max: case LayerVoteType::Heuristic: hasSkipOverrideLayer = true; break; default: // No action break; } if (hasExplicitExactOrMultiple && hasExplicitDefault && hasHighHint) { if (hasExplicitExactOrMultiple && hasExplicitDefault && hasHighHint && hasSkipOverrideLayer) { break; } } if (hasSkipOverrideLayer) { ALOGV("%s: Skipping due to vote(s): uid=%d", __func__, uid); continue; } // Layers with ExplicitExactOrMultiple expect touch boost if (globalSignals.touch && hasExplicitExactOrMultiple) { ALOGV("%s: Skipping for touch (input signal): uid=%d", __func__, uid); Loading services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp +85 −0 Original line number Diff line number Diff line Loading @@ -2240,6 +2240,46 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_Touch EXPECT_FALSE(actualRankedFrameRates.consideredSignals.touch); } TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_touchBoost_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<LayerRequirement> 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); Loading Loading @@ -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<LayerRequirement> 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; Loading Loading
services/surfaceflinger/Scheduler/RefreshRateSelector.cpp +70 −50 Original line number Diff line number Diff line Loading @@ -489,6 +489,20 @@ auto RefreshRateSelector::getRankedFrameRates(const std::vector<LayerRequirement return mGetRankedFrameRatesCache->result; } using LayerRequirementPtrs = std::vector<const RefreshRateSelector::LayerRequirement*>; using PerUidLayerRequirements = std::unordered_map<uid_t, LayerRequirementPtrs>; PerUidLayerRequirements groupLayersByUid( const std::vector<RefreshRateSelector::LayerRequirement>& 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<LayerRequirement>& layers, GlobalSignals signals, Fps pacesetterFps) const -> RankedFrameRates { Loading Loading @@ -525,6 +539,43 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi return {ranking, GlobalSignals{.powerOnImminent = true}}; } // A method for UI Toolkit to send the touch signal via "HighHint" category vote, // which will touch boost when there are no ExplicitDefault layer votes on the app. // At most one app can have the "HighHint" touch boost vote at a time. // This accounts for cases such as games that use `setFrameRate` // with Default compatibility to limit the frame rate and disabling touch boost. bool isAppTouchBoost = false; const auto layersByUid = groupLayersByUid(layers); for (const auto& [uid, layersWithSameUid] : layersByUid) { bool hasHighHint = false; bool hasExplicitDefault = false; for (const auto& layer : layersWithSameUid) { switch (layer->vote) { 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; Loading @@ -535,7 +586,6 @@ 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; Loading Loading @@ -563,11 +613,9 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi explicitGteLayers++; break; case LayerVoteType::ExplicitCategory: 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 { // HighHint does not count as an explicit signal from an app. It is a touch signal // sent from UI Toolkit. if (layer.frameRateCategory != FrameRateCategory::HighHint) { explicitCategoryVoteLayers++; } if (layer.frameRateCategory == FrameRateCategory::NoPreference) { Loading Loading @@ -882,14 +930,11 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi return explicitCategoryVoteLayers + noVoteLayers + explicitGteLayers != layers.size(); }; // A method for UI Toolkit to send the touch signal via "HighHint" category vote, // which will touch boost when there are no ExplicitDefault layer votes. This is an // incomplete solution but accounts for cases such as games that use `setFrameRate` with default // This accounts for cases such as games that use `setFrameRate` with Default // compatibility to limit the frame rate, which should not have touch boost. const bool hasInteraction = signals.touch || interactiveLayers > 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<; Loading Loading @@ -917,42 +962,6 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi return {ranking, kNoSignals}; } using LayerRequirementPtrs = std::vector<const RefreshRateSelector::LayerRequirement*>; using PerUidLayerRequirements = std::unordered_map<uid_t, LayerRequirementPtrs>; PerUidLayerRequirements groupLayersByUid( const std::vector<RefreshRateSelector::LayerRequirement>& 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<LayerRequirement>& layers, Fps displayRefreshRate, GlobalSignals globalSignals) const Loading Loading @@ -997,6 +1006,7 @@ auto RefreshRateSelector::getFrameRateOverrides(const std::vector<LayerRequireme bool hasExplicitExactOrMultiple = false; bool hasExplicitDefault = false; bool hasHighHint = false; bool hasSkipOverrideLayer = false; for (const auto& layer : layersWithSameUid) { switch (layer->vote) { case LayerVoteType::ExplicitExactOrMultiple: Loading @@ -1010,15 +1020,25 @@ auto RefreshRateSelector::getFrameRateOverrides(const std::vector<LayerRequireme hasHighHint = true; } break; case LayerVoteType::Max: case LayerVoteType::Heuristic: hasSkipOverrideLayer = true; break; default: // No action break; } if (hasExplicitExactOrMultiple && hasExplicitDefault && hasHighHint) { if (hasExplicitExactOrMultiple && hasExplicitDefault && hasHighHint && hasSkipOverrideLayer) { break; } } if (hasSkipOverrideLayer) { ALOGV("%s: Skipping due to vote(s): uid=%d", __func__, uid); continue; } // Layers with ExplicitExactOrMultiple expect touch boost if (globalSignals.touch && hasExplicitExactOrMultiple) { ALOGV("%s: Skipping for touch (input signal): uid=%d", __func__, uid); Loading
services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp +85 −0 Original line number Diff line number Diff line Loading @@ -2240,6 +2240,46 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_Touch EXPECT_FALSE(actualRankedFrameRates.consideredSignals.touch); } TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_touchBoost_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<LayerRequirement> 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); Loading Loading @@ -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<LayerRequirement> 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; Loading