SF: Move mode caching from Scheduler to RefreshRateConfigs
In the existing behavior Scheduler checks if the
layerReuquirements have changes since the last time
and only then calls into RefreshRateConfigs to
getBestRefreshRate. There are two problems with that
1. on the first iteration of the algorithm
mFeatures.contentRequirements is empty. If we happen
to have an empty list of current content requirements
(for example if all layers have NoVote), we
won't execute the refresh rate selection algorithm
and we'll end up with a wrong initial refresh rate.
2. the cached value needs to be invalided when one of
these change
- globalSignals
- supported display modes (happens on TV)
- display manager policy
Bug: 188872896
Test: atest SchedulerTest RefreshRateConfigsTest
Change-Id: I101f401522fae8358752e283d8375caa93957b6a
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index b062acd..9746076 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -190,6 +190,45 @@
RefreshRate RefreshRateConfigs::getBestRefreshRate(const std::vector<LayerRequirement>& layers,
const GlobalSignals& globalSignals,
GlobalSignals* outSignalsConsidered) const {
+ std::lock_guard lock(mLock);
+
+ if (auto cached = getCachedBestRefreshRate(layers, globalSignals, outSignalsConsidered)) {
+ return *cached;
+ }
+
+ GlobalSignals signalsConsidered;
+ RefreshRate result = getBestRefreshRateLocked(layers, globalSignals, &signalsConsidered);
+ lastBestRefreshRateInvocation.emplace(
+ GetBestRefreshRateInvocation{.layerRequirements = layers,
+ .globalSignals = globalSignals,
+ .outSignalsConsidered = signalsConsidered,
+ .resultingBestRefreshRate = result});
+ if (outSignalsConsidered) {
+ *outSignalsConsidered = signalsConsidered;
+ }
+ return result;
+}
+
+std::optional<RefreshRate> RefreshRateConfigs::getCachedBestRefreshRate(
+ const std::vector<LayerRequirement>& layers, const GlobalSignals& globalSignals,
+ GlobalSignals* outSignalsConsidered) const {
+ const bool sameAsLastCall = lastBestRefreshRateInvocation &&
+ lastBestRefreshRateInvocation->layerRequirements == layers &&
+ lastBestRefreshRateInvocation->globalSignals == globalSignals;
+
+ if (sameAsLastCall) {
+ if (outSignalsConsidered) {
+ *outSignalsConsidered = lastBestRefreshRateInvocation->outSignalsConsidered;
+ }
+ return lastBestRefreshRateInvocation->resultingBestRefreshRate;
+ }
+
+ return {};
+}
+
+RefreshRate RefreshRateConfigs::getBestRefreshRateLocked(
+ const std::vector<LayerRequirement>& layers, const GlobalSignals& globalSignals,
+ GlobalSignals* outSignalsConsidered) const {
ATRACE_CALL();
ALOGV("getBestRefreshRate %zu layers", layers.size());
@@ -206,8 +245,6 @@
}
};
- std::lock_guard lock(mLock);
-
int noVoteLayers = 0;
int minVoteLayers = 0;
int maxVoteLayers = 0;
@@ -592,6 +629,11 @@
void RefreshRateConfigs::setCurrentModeId(DisplayModeId modeId) {
std::lock_guard lock(mLock);
+
+ // Invalidate the cached invocation to getBestRefreshRate. This forces
+ // the refresh rate to be recomputed on the next call to getBestRefreshRate.
+ lastBestRefreshRateInvocation.reset();
+
mCurrentRefreshRate = mRefreshRates.at(modeId).get();
}
@@ -605,11 +647,16 @@
void RefreshRateConfigs::updateDisplayModes(const DisplayModes& modes,
DisplayModeId currentModeId) {
std::lock_guard lock(mLock);
+
// The current mode should be supported
LOG_ALWAYS_FATAL_IF(std::none_of(modes.begin(), modes.end(), [&](DisplayModePtr mode) {
return mode->getId() == currentModeId;
}));
+ // Invalidate the cached invocation to getBestRefreshRate. This forces
+ // the refresh rate to be recomputed on the next call to getBestRefreshRate.
+ lastBestRefreshRateInvocation.reset();
+
mRefreshRates.clear();
for (const auto& mode : modes) {
const auto modeId = mode->getId();
@@ -666,6 +713,7 @@
ALOGE("Invalid refresh rate policy: %s", policy.toString().c_str());
return BAD_VALUE;
}
+ lastBestRefreshRateInvocation.reset();
Policy previousPolicy = *getCurrentPolicyLocked();
mDisplayManagerPolicy = policy;
if (*getCurrentPolicyLocked() == previousPolicy) {
@@ -680,6 +728,7 @@
if (policy && !isPolicyValidLocked(*policy)) {
return BAD_VALUE;
}
+ lastBestRefreshRateInvocation.reset();
Policy previousPolicy = *getCurrentPolicyLocked();
mOverridePolicy = policy;
if (*getCurrentPolicyLocked() == previousPolicy) {
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index ee89149..342fde0 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -250,6 +250,10 @@
bool touch = false;
// True if the system hasn't seen any buffers posted to layers recently.
bool idle = false;
+
+ bool operator==(const GlobalSignals& other) const {
+ return touch == other.touch && idle == other.idle;
+ }
};
// Returns the refresh rate that fits best to the given layers.
@@ -350,6 +354,15 @@
const std::function<bool(const RefreshRate&)>& shouldAddRefreshRate,
std::vector<const RefreshRate*>* outRefreshRates) REQUIRES(mLock);
+ std::optional<RefreshRate> getCachedBestRefreshRate(const std::vector<LayerRequirement>& layers,
+ const GlobalSignals& globalSignals,
+ GlobalSignals* outSignalsConsidered) const
+ REQUIRES(mLock);
+
+ RefreshRate getBestRefreshRateLocked(const std::vector<LayerRequirement>& layers,
+ const GlobalSignals& globalSignals,
+ GlobalSignals* outSignalsConsidered) const REQUIRES(mLock);
+
// Returns the refresh rate with the highest score in the collection specified from begin
// to end. If there are more than one with the same highest refresh rate, the first one is
// returned.
@@ -414,6 +427,15 @@
const bool mEnableFrameRateOverride;
bool mSupportsFrameRateOverride;
+
+ struct GetBestRefreshRateInvocation {
+ std::vector<LayerRequirement> layerRequirements;
+ GlobalSignals globalSignals;
+ GlobalSignals outSignalsConsidered;
+ RefreshRate resultingBestRefreshRate;
+ };
+ mutable std::optional<GetBestRefreshRateInvocation> lastBestRefreshRateInvocation
+ GUARDED_BY(mLock);
};
} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 857071c..4b8cbfb 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -622,9 +622,6 @@
bool frameRateOverridesChanged;
{
std::lock_guard<std::mutex> lock(mFeatureStateLock);
- if (mFeatures.contentRequirements == summary) {
- return;
- }
mFeatures.contentRequirements = summary;
newModeId = calculateRefreshRateModeId(&consideredSignals);