Adding support for the setFrameRate() API to SurfaceFlinger path
- When choosing the max refresh rate in Layer History, check if
the layer has the bit set, if so use it.
- Disable touch boost/choosing config with max refresh rate,
when the layer has framerate set.
Test: Run unit test. Observe logs.
Test: Extend unit test to 10sec. Tap on screen while it's running.
Observe logs. Tap, should not reset the max refresh rate.
Change-Id: Ibe2689964c9f92788ace1b08c3521f156cb47524
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index 8219a7d..abf0cd6 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -43,6 +43,9 @@
namespace {
bool isLayerActive(const Layer& layer, const LayerInfo& info, nsecs_t threshold) {
+ if (layer.getFrameRate() > .0f) {
+ return layer.isVisible();
+ }
return layer.isVisible() && info.getLastUpdatedTime() >= threshold;
}
@@ -117,11 +120,32 @@
// Layers should be organized by priority
ALOGD("Layer has priority: %d", priority);
}
+ }
+ }
+ }
+
+ for (const auto& [weakLayer, info] : activeLayers()) {
+ const bool recent = info->isRecentlyActive(now);
+ auto layer = weakLayer.promote();
+ // Only use the layer if the reference still exists.
+ if (layer || CC_UNLIKELY(mTraceEnabled)) {
+ float refreshRate = 0.f;
+ // Default content refresh rate is only used when dealing with recent layers.
+ if (recent) {
+ refreshRate = info->getRefreshRate(now);
+ }
+ // Check if frame rate was set on layer.
+ float frameRate = layer->getFrameRate();
+ if (frameRate > 0.f) {
+ // Override content detection refresh rate, if it was set.
+ refreshRate = frameRate;
+ }
+ if (refreshRate > maxRefreshRate) {
maxRefreshRate = refreshRate;
}
if (CC_UNLIKELY(mTraceEnabled)) {
- trace(activeLayer, std::round(refreshRate));
+ trace(weakLayer, std::round(refreshRate));
}
}
}
@@ -175,6 +199,22 @@
mActiveLayersEnd = 0;
}
+bool LayerHistory::hasClientSpecifiedFrameRate() {
+ std::lock_guard lock(mLock);
+ for (const auto& [weakLayer, info] : activeLayers()) {
+ auto layer = weakLayer.promote();
+ if (layer) {
+ float frameRate = layer->getFrameRate();
+ // Found a layer that has a frame rate set on it.
+ if (fabs(frameRate) > 0.f) {
+ return true;
+ }
+ }
+ }
+ // Did not find any layers that have frame rate.
+ return false;
+}
+
} // namespace android::scheduler::impl
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index 188fa64..f217134 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -53,6 +53,9 @@
virtual Summary summarize(nsecs_t now) = 0;
virtual void clear() = 0;
+
+ // Checks whether any of the active layers have a desired frame rate bit set on them.
+ virtual bool hasClientSpecifiedFrameRate() = 0;
};
namespace impl {
@@ -75,6 +78,10 @@
void clear() override;
+ // Traverses all active layers and checks whether any of them have a desired frame
+ // rate bit set on them.
+ bool hasClientSpecifiedFrameRate() override;
+
private:
friend class android::scheduler::LayerHistoryTest;
friend TestableScheduler;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index c96eba4..0b645c4 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -422,18 +422,20 @@
}
void Scheduler::notifyTouchEvent() {
- if (mTouchTimer) {
- mTouchTimer->reset();
- }
-
- if (mSupportKernelTimer && mIdleTimer) {
- mIdleTimer->reset();
- }
-
// Touch event will boost the refresh rate to performance.
- // Clear Layer History to get fresh FPS detection
- if (mLayerHistory) {
+ // Clear Layer History to get fresh FPS detection.
+ // NOTE: Instead of checking all the layers, we should be checking the layer
+ // that is currently on top. b/142507166 will give us this capability.
+ if (mLayerHistory && !mLayerHistory->hasClientSpecifiedFrameRate()) {
mLayerHistory->clear();
+
+ if (mTouchTimer) {
+ mTouchTimer->reset();
+ }
+
+ if (mSupportKernelTimer && mIdleTimer) {
+ mIdleTimer->reset();
+ }
}
}
@@ -533,25 +535,31 @@
return mRefreshRateConfigs.getCurrentRefreshRate().configId;
}
- // If Display Power is not in normal operation we want to be in performance mode.
- // When coming back to normal mode, a grace period is given with DisplayPowerTimer
- if (!mFeatures.isDisplayPowerStateNormal || mFeatures.displayPowerTimer == TimerState::Reset) {
- return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
- }
+ // If the layer history doesn't have the frame rate specified, use the old path. NOTE:
+ // if we remove the kernel idle timer, and use our internal idle timer, this code will have to
+ // be refactored.
+ if (!mLayerHistory->hasClientSpecifiedFrameRate()) {
+ // If Display Power is not in normal operation we want to be in performance mode.
+ // When coming back to normal mode, a grace period is given with DisplayPowerTimer
+ if (!mFeatures.isDisplayPowerStateNormal ||
+ mFeatures.displayPowerTimer == TimerState::Reset) {
+ return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
+ }
- // As long as touch is active we want to be in performance mode
- if (mFeatures.touch == TouchState::Active) {
- return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
- }
+ // As long as touch is active we want to be in performance mode
+ if (mFeatures.touch == TouchState::Active) {
+ return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
+ }
- // If timer has expired as it means there is no new content on the screen
- if (mFeatures.idleTimer == TimerState::Expired) {
- return mRefreshRateConfigs.getMinRefreshRateByPolicy().configId;
- }
+ // If timer has expired as it means there is no new content on the screen
+ if (mFeatures.idleTimer == TimerState::Expired) {
+ return mRefreshRateConfigs.getMinRefreshRateByPolicy().configId;
+ }
- // If content detection is off we choose performance as we don't know the content fps
- if (mFeatures.contentDetection == ContentDetectionState::Off) {
- return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
+ // If content detection is off we choose performance as we don't know the content fps
+ if (mFeatures.contentDetection == ContentDetectionState::Off) {
+ return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
+ }
}
// Content detection is on, find the appropriate refresh rate with minimal error