Merge "SurfaceFlinger: frame rate heuristic during config change" into rvc-dev am: 36725c77ca
Change-Id: I899cf48235bb79097b2198401bbe9ab66aa99c0c
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index a1ae35c..d5bebf6 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -52,6 +52,8 @@
// Sets the display size. Client is responsible for synchronization.
virtual void setDisplayArea(uint32_t displayArea) = 0;
+ virtual void setConfigChangePending(bool pending) = 0;
+
// Marks the layer as active, and records the given state to its history.
virtual void record(Layer*, nsecs_t presentTime, nsecs_t now) = 0;
@@ -78,6 +80,8 @@
void setDisplayArea(uint32_t /*displayArea*/) override {}
+ 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;
@@ -134,6 +138,8 @@
// Sets the display size. Client is responsible for synchronization.
void setDisplayArea(uint32_t displayArea) override { mDisplayArea = displayArea; }
+ 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;
@@ -178,6 +184,9 @@
// Whether to use priority sent from WindowManager to determine the relevancy of the layer.
const bool mUseFrameRatePriority;
+
+ // Whether a config change is in progress or not
+ std::atomic<bool> mConfigChangePending = false;
};
} // namespace impl
diff --git a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
index 120a60f..afc8c4f 100644
--- a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
@@ -103,7 +103,7 @@
LOG_FATAL_IF(it == mLayerInfos.end(), "%s: unknown layer %p", __FUNCTION__, layer);
const auto& info = it->second;
- info->setLastPresentTime(presentTime, now);
+ info->setLastPresentTime(presentTime, now, 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 255eac6..c16387a 100644
--- a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
@@ -34,12 +34,15 @@
mDefaultVote(defaultVote),
mLayerVote({defaultVote, 0.0f}) {}
-void LayerInfoV2::setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now) {
+void LayerInfoV2::setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now,
+ bool pendingConfigChange) {
lastPresentTime = std::max(lastPresentTime, static_cast<nsecs_t>(0));
mLastUpdatedTime = std::max(lastPresentTime, now);
- FrameTimeData frameTime = {.presetTime = lastPresentTime, .queueTime = mLastUpdatedTime};
+ FrameTimeData frameTime = {.presetTime = lastPresentTime,
+ .queueTime = mLastUpdatedTime,
+ .pendingConfigChange = pendingConfigChange};
mFrameTimes.push_back(frameTime);
if (mFrameTimes.size() > HISTORY_SIZE) {
@@ -80,21 +83,20 @@
return true;
}
-std::optional<float> LayerInfoV2::calculateRefreshRateIfPossible() {
- static constexpr float MARGIN = 1.0f; // 1Hz
-
- if (!hasEnoughDataForHeuristic()) {
- ALOGV("Not enough data");
- return std::nullopt;
- }
-
- // Calculate the refresh rate by finding the average delta between frames
+std::pair<nsecs_t, bool> LayerInfoV2::calculateAverageFrameTime() const {
nsecs_t totalPresentTimeDeltas = 0;
nsecs_t totalQueueTimeDeltas = 0;
- auto missingPresentTime = false;
+ bool missingPresentTime = false;
+ int numFrames = 0;
for (auto it = mFrameTimes.begin(); it != mFrameTimes.end() - 1; ++it) {
+ // Ignore frames captured during a config change
+ if (it->pendingConfigChange || (it + 1)->pendingConfigChange) {
+ continue;
+ }
+
totalQueueTimeDeltas +=
std::max(((it + 1)->queueTime - it->queueTime), mHighRefreshRatePeriod);
+ numFrames++;
if (it->presetTime == 0 || (it + 1)->presetTime == 0) {
missingPresentTime = true;
@@ -105,11 +107,6 @@
std::max(((it + 1)->presetTime - it->presetTime), mHighRefreshRatePeriod);
}
- // If there are no presentation timestamps provided we can't calculate the refresh rate
- if (missingPresentTime && mLastReportedRefreshRate == 0) {
- return std::nullopt;
- }
-
// Calculate the average frame time based on presentation timestamps. If those
// doesn't exist, we look at the time the buffer was queued only. We can do that only if
// we calculated a refresh rate based on presentation timestamps in the past. The reason
@@ -117,13 +114,18 @@
// when implementing render ahead for specific refresh rates. When hwui no longer provides
// presentation timestamps we look at the queue time to see if the current refresh rate still
// matches the content.
- const float averageFrameTime =
+ const auto averageFrameTime =
static_cast<float>(missingPresentTime ? totalQueueTimeDeltas : totalPresentTimeDeltas) /
- (mFrameTimes.size() - 1);
+ numFrames;
+ return {static_cast<nsecs_t>(averageFrameTime), missingPresentTime};
+}
- // Now once we calculated the refresh rate we need to make sure that all the frames we captured
- // are evenly distributed and we don't calculate the average across some burst of frames.
+bool LayerInfoV2::isRefreshRateStable(nsecs_t averageFrameTime, bool missingPresentTime) const {
for (auto it = mFrameTimes.begin(); it != mFrameTimes.end() - 1; ++it) {
+ // Ignore frames captured during a config change
+ if (it->pendingConfigChange || (it + 1)->pendingConfigChange) {
+ continue;
+ }
const auto presentTimeDeltas = [&] {
const auto delta = missingPresentTime ? (it + 1)->queueTime - it->queueTime
: (it + 1)->presetTime - it->presetTime;
@@ -131,10 +133,32 @@
}();
if (std::abs(presentTimeDeltas - averageFrameTime) > 2 * averageFrameTime) {
- return std::nullopt;
+ return false;
}
}
+ return true;
+}
+
+std::optional<float> LayerInfoV2::calculateRefreshRateIfPossible() {
+ static constexpr float MARGIN = 1.0f; // 1Hz
+
+ if (!hasEnoughDataForHeuristic()) {
+ ALOGV("Not enough data");
+ return std::nullopt;
+ }
+
+ const auto [averageFrameTime, missingPresentTime] = calculateAverageFrameTime();
+
+ // If there are no presentation timestamps provided we can't calculate the refresh rate
+ if (missingPresentTime && mLastReportedRefreshRate == 0) {
+ return std::nullopt;
+ }
+
+ if (!isRefreshRateStable(averageFrameTime, missingPresentTime)) {
+ return std::nullopt;
+ }
+
const auto refreshRate = 1e9f / averageFrameTime;
if (std::abs(refreshRate - mLastReportedRefreshRate) > MARGIN) {
mLastReportedRefreshRate = refreshRate;
diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.h b/services/surfaceflinger/Scheduler/LayerInfoV2.h
index 97c7017..ccd6be4 100644
--- a/services/surfaceflinger/Scheduler/LayerInfoV2.h
+++ b/services/surfaceflinger/Scheduler/LayerInfoV2.h
@@ -63,7 +63,7 @@
// 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);
+ void setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now, bool pendingConfigChange);
// Sets an explicit layer vote. This usually comes directly from the application via
// ANativeWindow_setFrameRate API
@@ -93,11 +93,14 @@
struct FrameTimeData {
nsecs_t presetTime; // desiredPresentTime, if provided
nsecs_t queueTime; // buffer queue time
+ bool pendingConfigChange;
};
bool isFrequent(nsecs_t now) const;
bool hasEnoughDataForHeuristic() const;
std::optional<float> calculateRefreshRateIfPossible();
+ std::pair<nsecs_t, bool> calculateAverageFrameTime() const;
+ bool isRefreshRateStable(nsecs_t averageFrameTime, bool missingPresentTime) const;
const std::string mName;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 4eef81d..7c2af23 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -423,6 +423,12 @@
}
}
+void Scheduler::setConfigChangePending(bool pending) {
+ if (mLayerHistory) {
+ mLayerHistory->setConfigChangePending(pending);
+ }
+}
+
void Scheduler::chooseRefreshRateForContent() {
if (!mLayerHistory) return;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 6eabfd2..066e9ca 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -119,6 +119,7 @@
// Layers are registered on creation, and unregistered when the weak reference expires.
void registerLayer(Layer*);
void recordLayerHistory(Layer*, nsecs_t presentTime);
+ void setConfigChangePending(bool pending);
// Detects content using layer history, and selects a matching refresh rate.
void chooseRefreshRateForContent();
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 18f789e..2d25319 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1010,6 +1010,7 @@
mPhaseConfiguration->setRefreshRateFps(refreshRate.getFps());
mVSyncModulator->setPhaseOffsets(mPhaseConfiguration->getCurrentOffsets());
+ mScheduler->setConfigChangePending(true);
}
if (mRefreshRateOverlay) {
@@ -1090,6 +1091,7 @@
mScheduler->resyncToHardwareVsync(true, refreshRate.getVsyncPeriod());
mPhaseConfiguration->setRefreshRateFps(refreshRate.getFps());
mVSyncModulator->setPhaseOffsets(mPhaseConfiguration->getCurrentOffsets());
+ mScheduler->setConfigChangePending(false);
}
void SurfaceFlinger::performSetActiveConfig() {