SurfaceFlinger: more aggressive infrequent layer detection
Change the algorithm that chooses the refresh rate to treat layers as
infrequent unless proven otherwise. This change helps with multiple
switches during scenarios of blinking cursor where the detection of
infrequent layer is too long. The down side on this change is that
animations will be considered infrequent as well for the first few frames.
However the touch boost is a good mitigation of this.
Test: Typing in Messages and observe refresh rate
Test: Settings->About->up time and observe refresh rate
Bug: 155062712
Bug: 156654519
Change-Id: I317c69bd063df5d70f2d5705163cf61c1c9b1fff
diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
index b7d0bdd..255eac6 100644
--- a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
@@ -27,8 +27,10 @@
namespace android::scheduler {
-LayerInfoV2::LayerInfoV2(nsecs_t highRefreshRatePeriod, LayerHistory::LayerVoteType defaultVote)
- : mHighRefreshRatePeriod(highRefreshRatePeriod),
+LayerInfoV2::LayerInfoV2(const std::string& name, nsecs_t highRefreshRatePeriod,
+ LayerHistory::LayerVoteType defaultVote)
+ : mName(name),
+ mHighRefreshRatePeriod(highRefreshRatePeriod),
mDefaultVote(defaultVote),
mLayerVote({defaultVote, 0.0f}) {}
@@ -45,42 +47,23 @@
}
}
-bool LayerInfoV2::isFrameTimeValid(const FrameTimeData& frameTime) const {
- return frameTime.queueTime >= std::chrono::duration_cast<std::chrono::nanoseconds>(
- mFrameTimeValidSince.time_since_epoch())
- .count();
-}
-
bool LayerInfoV2::isFrequent(nsecs_t now) const {
- // Find the first valid frame time
- auto it = mFrameTimes.begin();
- for (; it != mFrameTimes.end(); ++it) {
- if (isFrameTimeValid(*it)) {
- break;
+ for (auto it = mFrameTimes.crbegin(); it != mFrameTimes.crend(); ++it) {
+ if (now - it->queueTime >= MAX_FREQUENT_LAYER_PERIOD_NS.count()) {
+ ALOGV("%s infrequent (last frame is %.2fms ago", mName.c_str(),
+ (now - mFrameTimes.back().queueTime) / 1e6f);
+ return false;
+ }
+
+ const auto numFrames = std::distance(mFrameTimes.crbegin(), it + 1);
+ if (numFrames >= FREQUENT_LAYER_WINDOW_SIZE) {
+ ALOGV("%s frequent (burst of %zu frames", mName.c_str(), numFrames);
+ return true;
}
}
- // If we know nothing about this layer we consider it as frequent as it might be the start
- // of an animation.
- if (std::distance(it, mFrameTimes.end()) < FREQUENT_LAYER_WINDOW_SIZE) {
- return true;
- }
-
- // Find the first active frame
- for (; it != mFrameTimes.end(); ++it) {
- if (it->queueTime >= getActiveLayerThreshold(now)) {
- break;
- }
- }
-
- const auto numFrames = std::distance(it, mFrameTimes.end());
- if (numFrames < FREQUENT_LAYER_WINDOW_SIZE) {
- return false;
- }
-
- // Layer is considered frequent if the average frame rate is higher than the threshold
- const auto totalTime = mFrameTimes.back().queueTime - it->queueTime;
- return (1e9f * (numFrames - 1)) / totalTime >= MIN_FPS_FOR_FREQUENT_LAYER;
+ ALOGV("%s infrequent (not enough frames %zu)", mName.c_str(), mFrameTimes.size());
+ return false;
}
bool LayerInfoV2::hasEnoughDataForHeuristic() const {
@@ -89,10 +72,6 @@
return false;
}
- if (!isFrameTimeValid(mFrameTimes.front())) {
- return false;
- }
-
if (mFrameTimes.size() < HISTORY_SIZE &&
mFrameTimes.back().queueTime - mFrameTimes.front().queueTime < HISTORY_TIME.count()) {
return false;
@@ -167,18 +146,22 @@
std::pair<LayerHistory::LayerVoteType, float> LayerInfoV2::getRefreshRate(nsecs_t now) {
if (mLayerVote.type != LayerHistory::LayerVoteType::Heuristic) {
+ ALOGV("%s voted %d ", mName.c_str(), static_cast<int>(mLayerVote.type));
return {mLayerVote.type, mLayerVote.fps};
}
if (!isFrequent(now)) {
+ ALOGV("%s is infrequent", mName.c_str());
return {LayerHistory::LayerVoteType::Min, 0};
}
auto refreshRate = calculateRefreshRateIfPossible();
if (refreshRate.has_value()) {
+ ALOGV("%s calculated refresh rate: %.2f", mName.c_str(), refreshRate.value());
return {LayerHistory::LayerVoteType::Heuristic, refreshRate.value()};
}
+ ALOGV("%s Max (can't resolve refresh rate", mName.c_str());
return {LayerHistory::LayerVoteType::Max, 0};
}