Merge "Support HIGH_INTERACTIVE category in native" into main
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index a98ea86..969a5cf 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -1095,10 +1095,19 @@
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 2dd3c62..9c4f7a5 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp
@@ -532,6 +532,8 @@
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 e06221a..c3709e5 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
@@ -420,6 +420,11 @@
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 @@
int explicitExact = 0;
int explicitGteLayers = 0;
int explicitCategoryVoteLayers = 0;
+ int interactiveLayers = 0;
int seamedFocusedLayers = 0;
int categorySmoothSwitchOnlyLayers = 0;
@@ -534,7 +540,13 @@
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 @@
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 @@
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 2806450..84ef89f 100644
--- a/services/surfaceflinger/Scheduler/include/scheduler/Fps.h
+++ b/services/surfaceflinger/Scheduler/include/scheduler/Fps.h
@@ -88,6 +88,7 @@
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 ba32c68..55b20b3 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -650,7 +650,7 @@
// │ └── 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 @@
// │ │ └── 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 @@
// │ │ └── 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 0cacf81..1e526ba 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
@@ -1607,6 +1607,82 @@
}
}
+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) {