SurfaceFlinger: record layer history for TX with eAnimation
If a transaction is posted with ISurfaceComposer::eAnimation flag,
record it with layer history. Layers with eAnimation are considered
animating and will vote for peak refresh rate.
Bug: 157695685
Test: Play 24fps video in YouTube PIP mode with setFrameRate and rotate the device - no jank
Test: Chrome playing video - no refresh rate switching
Test: Hide/Show keyboard when inputting text
Test: Running Hay Day and observing refresh rate
Change-Id: If62e11b395c44d9e5fd40b74864fefd068953413
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index 8958d9a..2925109 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -79,7 +79,8 @@
mLayerInfos.emplace_back(layer, std::move(info));
}
-void LayerHistory::record(Layer* layer, nsecs_t presentTime, nsecs_t now) {
+void LayerHistory::record(Layer* layer, nsecs_t presentTime, nsecs_t now,
+ LayerUpdateType /*updateType*/) {
std::lock_guard lock(mLock);
const auto it = std::find_if(mLayerInfos.begin(), mLayerInfos.end(),
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index d5bebf6..acd76b0 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -52,10 +52,18 @@
// Sets the display size. Client is responsible for synchronization.
virtual void setDisplayArea(uint32_t displayArea) = 0;
+ // Sets whether a config change is pending to be applied
virtual void setConfigChangePending(bool pending) = 0;
+ // Represents which layer activity is recorded
+ enum class LayerUpdateType {
+ Buffer, // a new buffer queued
+ AnimationTX, // a new transaction with eAnimation flag set
+ SetFrameRate, // setFrameRate API was called
+ };
+
// Marks the layer as active, and records the given state to its history.
- virtual void record(Layer*, nsecs_t presentTime, nsecs_t now) = 0;
+ virtual void record(Layer*, nsecs_t presentTime, nsecs_t now, LayerUpdateType updateType) = 0;
using Summary = std::vector<RefreshRateConfigs::LayerRequirement>;
@@ -83,7 +91,7 @@
void setConfigChangePending(bool /*pending*/) override {}
// Marks the layer as active, and records the given state to its history.
- void record(Layer*, nsecs_t presentTime, nsecs_t now) override;
+ void record(Layer*, nsecs_t presentTime, nsecs_t now, LayerUpdateType updateType) override;
// Rebuilds sets of active/inactive layers, and accumulates stats for active layers.
android::scheduler::LayerHistory::Summary summarize(nsecs_t now) override;
@@ -141,7 +149,7 @@
void setConfigChangePending(bool pending) override { mConfigChangePending = pending; }
// Marks the layer as active, and records the given state to its history.
- void record(Layer*, nsecs_t presentTime, nsecs_t now) override;
+ void record(Layer*, nsecs_t presentTime, nsecs_t now, LayerUpdateType updateType) override;
// Rebuilds sets of active/inactive layers, and accumulates stats for active layers.
android::scheduler::LayerHistory::Summary summarize(nsecs_t /*now*/) override;
diff --git a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
index 6570b1a..316000c 100644
--- a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
@@ -99,7 +99,8 @@
mLayerInfos.emplace_back(layer, std::move(info));
}
-void LayerHistoryV2::record(Layer* layer, nsecs_t presentTime, nsecs_t now) {
+void LayerHistoryV2::record(Layer* layer, nsecs_t presentTime, nsecs_t now,
+ LayerUpdateType updateType) {
std::lock_guard lock(mLock);
const auto it = std::find_if(mLayerInfos.begin(), mLayerInfos.end(),
@@ -107,7 +108,7 @@
LOG_FATAL_IF(it == mLayerInfos.end(), "%s: unknown layer %p", __FUNCTION__, layer);
const auto& info = it->second;
- info->setLastPresentTime(presentTime, now, mConfigChangePending);
+ info->setLastPresentTime(presentTime, now, updateType, mConfigChangePending);
// Activate layer if inactive.
if (const auto end = activeLayers().end(); it >= end) {
diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
index 25dca39..82da007 100644
--- a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
@@ -35,18 +35,24 @@
mLayerVote({defaultVote, 0.0f}) {}
void LayerInfoV2::setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now,
- bool pendingConfigChange) {
+ LayerUpdateType updateType, bool pendingConfigChange) {
lastPresentTime = std::max(lastPresentTime, static_cast<nsecs_t>(0));
mLastUpdatedTime = std::max(lastPresentTime, now);
-
- FrameTimeData frameTime = {.presetTime = lastPresentTime,
- .queueTime = mLastUpdatedTime,
- .pendingConfigChange = pendingConfigChange};
-
- mFrameTimes.push_back(frameTime);
- if (mFrameTimes.size() > HISTORY_SIZE) {
- mFrameTimes.pop_front();
+ switch (updateType) {
+ case LayerUpdateType::AnimationTX:
+ mLastAnimationTime = std::max(lastPresentTime, now);
+ break;
+ case LayerUpdateType::SetFrameRate:
+ case LayerUpdateType::Buffer:
+ FrameTimeData frameTime = {.presetTime = lastPresentTime,
+ .queueTime = mLastUpdatedTime,
+ .pendingConfigChange = pendingConfigChange};
+ mFrameTimes.push_back(frameTime);
+ if (mFrameTimes.size() > HISTORY_SIZE) {
+ mFrameTimes.pop_front();
+ }
+ break;
}
}
@@ -81,6 +87,10 @@
return (1e9f * (numFrames - 1)) / totalTime >= MIN_FPS_FOR_FREQUENT_LAYER;
}
+bool LayerInfoV2::isAnimating(nsecs_t now) const {
+ return mLastAnimationTime >= getActiveLayerThreshold(now);
+}
+
bool LayerInfoV2::hasEnoughDataForHeuristic() const {
// The layer had to publish at least HISTORY_SIZE or HISTORY_TIME of updates
if (mFrameTimes.size() < 2) {
@@ -190,6 +200,11 @@
return {mLayerVote.type, mLayerVote.fps};
}
+ if (isAnimating(now)) {
+ ALOGV("%s is animating", mName.c_str());
+ return {LayerHistory::LayerVoteType::Max, 0};
+ }
+
if (!isFrequent(now)) {
ALOGV("%s is infrequent", mName.c_str());
return {LayerHistory::LayerVoteType::Min, 0};
diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.h b/services/surfaceflinger/Scheduler/LayerInfoV2.h
index 5f50d5a..9e6783f 100644
--- a/services/surfaceflinger/Scheduler/LayerInfoV2.h
+++ b/services/surfaceflinger/Scheduler/LayerInfoV2.h
@@ -43,6 +43,8 @@
// Stores history of present times and refresh rates for a layer.
class LayerInfoV2 {
+ using LayerUpdateType = LayerHistory::LayerUpdateType;
+
// Layer is considered frequent if the earliest value in the window of most recent present times
// is within a threshold. If a layer is infrequent, its average refresh rate is disregarded in
// favor of a low refresh rate.
@@ -63,7 +65,8 @@
// Records the last requested present time. It also stores information about when
// the layer was last updated. If the present time is farther in the future than the
// updated time, the updated time is the present time.
- void setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now, bool pendingConfigChange);
+ void setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now, LayerUpdateType updateType,
+ bool pendingConfigChange);
// Sets an explicit layer vote. This usually comes directly from the application via
// ANativeWindow_setFrameRate API
@@ -107,6 +110,7 @@
};
bool isFrequent(nsecs_t now) const;
+ bool isAnimating(nsecs_t now) const;
bool hasEnoughDataForHeuristic() const;
std::optional<float> calculateRefreshRateIfPossible();
std::pair<nsecs_t, bool> calculateAverageFrameTime() const;
@@ -121,6 +125,8 @@
nsecs_t mLastUpdatedTime = 0;
+ nsecs_t mLastAnimationTime = 0;
+
float mLastReportedRefreshRate = 0.0f;
// Holds information about the layer vote
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 7c2af23..d874c53 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -417,9 +417,10 @@
}
}
-void Scheduler::recordLayerHistory(Layer* layer, nsecs_t presentTime) {
+void Scheduler::recordLayerHistory(Layer* layer, nsecs_t presentTime,
+ LayerHistory::LayerUpdateType updateType) {
if (mLayerHistory) {
- mLayerHistory->record(layer, presentTime, systemTime());
+ mLayerHistory->record(layer, presentTime, systemTime(), updateType);
}
}
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 066e9ca..c519826 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -39,6 +39,7 @@
namespace android {
using namespace std::chrono_literals;
+using scheduler::LayerHistory;
class DispSync;
class FenceTime;
@@ -118,7 +119,7 @@
// Layers are registered on creation, and unregistered when the weak reference expires.
void registerLayer(Layer*);
- void recordLayerHistory(Layer*, nsecs_t presentTime);
+ void recordLayerHistory(Layer*, nsecs_t presentTime, LayerHistory::LayerUpdateType updateType);
void setConfigChangePending(bool pending);
// Detects content using layer history, and selects a matching refresh rate.
@@ -211,7 +212,7 @@
std::unique_ptr<EventControlThread> mEventControlThread;
// Used to choose refresh rate if content detection is enabled.
- std::unique_ptr<scheduler::LayerHistory> mLayerHistory;
+ std::unique_ptr<LayerHistory> mLayerHistory;
// Whether to use idle timer callbacks that support the kernel timer.
const bool mSupportKernelTimer;
@@ -236,7 +237,7 @@
TimerState displayPowerTimer = TimerState::Expired;
std::optional<HwcConfigIndexType> configId;
- scheduler::LayerHistory::Summary contentRequirements;
+ LayerHistory::Summary contentRequirements;
bool isDisplayPowerStateNormal = true;
} mFeatures GUARDED_BY(mFeatureStateLock);