SF: Simplify getBestRefreshRate caching
Cache the arguments/result as std::pair by removing the out parameter
for GlobalSignals.
Bug: 185535769
Test: libsurfaceflinger_unittest
Change-Id: Ibfb2aa4ca327b378844554bcd96620f84fc0460a
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 3becb5c..3b9cfa6 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -38,6 +38,8 @@
namespace android::scheduler {
namespace {
+constexpr RefreshRateConfigs::GlobalSignals kNoSignals;
+
std::string formatLayerInfo(const RefreshRateConfigs::LayerRequirement& layer, float weight) {
return base::StringPrintf("%s (type=%s, weight=%.2f seamlessness=%s) %s", layer.name.c_str(),
ftl::enum_string(layer.vote).c_str(), weight,
@@ -235,63 +237,26 @@
float score;
};
-RefreshRate RefreshRateConfigs::getBestRefreshRate(const std::vector<LayerRequirement>& layers,
- GlobalSignals globalSignals,
- GlobalSignals* outSignalsConsidered) const {
+auto RefreshRateConfigs::getBestRefreshRate(const std::vector<LayerRequirement>& layers,
+ GlobalSignals signals) const
+ -> std::pair<RefreshRate, GlobalSignals> {
std::lock_guard lock(mLock);
- if (auto cached = getCachedBestRefreshRate(layers, globalSignals, outSignalsConsidered)) {
- return *cached;
+ if (mGetBestRefreshRateCache &&
+ mGetBestRefreshRateCache->arguments == std::make_pair(layers, signals)) {
+ return mGetBestRefreshRateCache->result;
}
- GlobalSignals signalsConsidered;
- RefreshRate result = getBestRefreshRateLocked(layers, globalSignals, &signalsConsidered);
- lastBestRefreshRateInvocation.emplace(
- GetBestRefreshRateInvocation{.layerRequirements = layers,
- .globalSignals = globalSignals,
- .outSignalsConsidered = signalsConsidered,
- .resultingBestRefreshRate = result});
- if (outSignalsConsidered) {
- *outSignalsConsidered = signalsConsidered;
- }
+ const auto result = getBestRefreshRateLocked(layers, signals);
+ mGetBestRefreshRateCache = GetBestRefreshRateCache{{layers, signals}, result};
return result;
}
-std::optional<RefreshRate> RefreshRateConfigs::getCachedBestRefreshRate(
- const std::vector<LayerRequirement>& layers, 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, GlobalSignals globalSignals,
- GlobalSignals* outSignalsConsidered) const {
+auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequirement>& layers,
+ GlobalSignals signals) const
+ -> std::pair<RefreshRate, GlobalSignals> {
ATRACE_CALL();
- ALOGV("getBestRefreshRate %zu layers", layers.size());
-
- if (outSignalsConsidered) *outSignalsConsidered = {};
- const auto setTouchConsidered = [&] {
- if (outSignalsConsidered) {
- outSignalsConsidered->touch = true;
- }
- };
-
- const auto setIdleConsidered = [&] {
- if (outSignalsConsidered) {
- outSignalsConsidered->idle = true;
- }
- };
+ ALOGV("%s: %zu layers", __func__, layers.size());
int noVoteLayers = 0;
int minVoteLayers = 0;
@@ -301,6 +266,7 @@
int explicitExact = 0;
float maxExplicitWeight = 0;
int seamedFocusedLayers = 0;
+
for (const auto& layer : layers) {
switch (layer.vote) {
case LayerVoteType::NoVote:
@@ -349,10 +315,9 @@
// Consider the touch event if there are no Explicit* layers. Otherwise wait until after we've
// selected a refresh rate to see if we should apply touch boost.
- if (globalSignals.touch && !hasExplicitVoteLayers) {
+ if (signals.touch && !hasExplicitVoteLayers) {
ALOGV("TouchBoost - choose %s", getMaxRefreshRateByPolicyLocked().getName().c_str());
- setTouchConsidered();
- return getMaxRefreshRateByPolicyLocked(anchorGroup);
+ return {getMaxRefreshRateByPolicyLocked(anchorGroup), GlobalSignals{.touch = true}};
}
// If the primary range consists of a single refresh rate then we can only
@@ -361,23 +326,21 @@
const bool primaryRangeIsSingleRate =
isApproxEqual(policy->primaryRange.min, policy->primaryRange.max);
- if (!globalSignals.touch && globalSignals.idle &&
- !(primaryRangeIsSingleRate && hasExplicitVoteLayers)) {
+ if (!signals.touch && signals.idle && !(primaryRangeIsSingleRate && hasExplicitVoteLayers)) {
ALOGV("Idle - choose %s", getMinRefreshRateByPolicyLocked().getName().c_str());
- setIdleConsidered();
- return getMinRefreshRateByPolicyLocked();
+ return {getMinRefreshRateByPolicyLocked(), GlobalSignals{.idle = true}};
}
if (layers.empty() || noVoteLayers == layers.size()) {
const auto& refreshRate = getMaxRefreshRateByPolicyLocked(anchorGroup);
ALOGV("no layers with votes - choose %s", refreshRate.getName().c_str());
- return refreshRate;
+ return {refreshRate, kNoSignals};
}
// Only if all layers want Min we should return Min
if (noVoteLayers + minVoteLayers == layers.size()) {
ALOGV("all layers Min - choose %s", getMinRefreshRateByPolicyLocked().getName().c_str());
- return getMinRefreshRateByPolicyLocked();
+ return {getMinRefreshRateByPolicyLocked(), kNoSignals};
}
// Find the best refresh rate based on score
@@ -466,9 +429,9 @@
[](RefreshRateScore score) { return score.score == 0; })) {
const auto& refreshRate = getMaxRefreshRateByPolicyLocked(anchorGroup);
ALOGV("layers not scored - choose %s", refreshRate.getName().c_str());
- return refreshRate;
+ return {refreshRate, kNoSignals};
} else {
- return *bestRefreshRate;
+ return {*bestRefreshRate, kNoSignals};
}
}
@@ -490,14 +453,13 @@
using fps_approx_ops::operator<;
- if (globalSignals.touch && explicitDefaultVoteLayers == 0 && touchBoostForExplicitExact &&
+ if (signals.touch && explicitDefaultVoteLayers == 0 && touchBoostForExplicitExact &&
bestRefreshRate->getFps() < touchRefreshRate.getFps()) {
- setTouchConsidered();
ALOGV("TouchBoost - choose %s", touchRefreshRate.getName().c_str());
- return touchRefreshRate;
+ return {touchRefreshRate, GlobalSignals{.touch = true}};
}
- return *bestRefreshRate;
+ return {*bestRefreshRate, kNoSignals};
}
std::unordered_map<uid_t, std::vector<const RefreshRateConfigs::LayerRequirement*>>
@@ -699,7 +661,7 @@
// Invalidate the cached invocation to getBestRefreshRate. This forces
// the refresh rate to be recomputed on the next call to getBestRefreshRate.
- lastBestRefreshRateInvocation.reset();
+ mGetBestRefreshRateCache.reset();
mCurrentRefreshRate = mRefreshRates.at(modeId).get();
}
@@ -741,7 +703,7 @@
// Invalidate the cached invocation to getBestRefreshRate. This forces
// the refresh rate to be recomputed on the next call to getBestRefreshRate.
- lastBestRefreshRateInvocation.reset();
+ mGetBestRefreshRateCache.reset();
mRefreshRates.clear();
for (const auto& mode : modes) {
@@ -800,7 +762,7 @@
ALOGE("Invalid refresh rate policy: %s", policy.toString().c_str());
return BAD_VALUE;
}
- lastBestRefreshRateInvocation.reset();
+ mGetBestRefreshRateCache.reset();
Policy previousPolicy = *getCurrentPolicyLocked();
mDisplayManagerPolicy = policy;
if (*getCurrentPolicyLocked() == previousPolicy) {
@@ -815,7 +777,7 @@
if (policy && !isPolicyValidLocked(*policy)) {
return BAD_VALUE;
}
- lastBestRefreshRateInvocation.reset();
+ mGetBestRefreshRateCache.reset();
Policy previousPolicy = *getCurrentPolicyLocked();
mOverridePolicy = policy;
if (*getCurrentPolicyLocked() == previousPolicy) {
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 7ef95f9..ade1787 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -20,6 +20,7 @@
#include <numeric>
#include <optional>
#include <type_traits>
+#include <utility>
#include <android-base/stringprintf.h>
#include <gui/DisplayEventReceiver.h>
@@ -249,11 +250,10 @@
}
};
- // Returns the refresh rate that best fits the given layers. outSignalsConsidered returns
- // whether the refresh rate was chosen based on touch boost and/or idle timer.
- RefreshRate getBestRefreshRate(const std::vector<LayerRequirement>&, GlobalSignals,
- GlobalSignals* outSignalsConsidered = nullptr) const
- EXCLUDES(mLock);
+ // Returns the refresh rate that best fits the given layers, and whether the refresh rate was
+ // chosen based on touch boost and/or idle timer.
+ std::pair<RefreshRate, GlobalSignals> getBestRefreshRate(const std::vector<LayerRequirement>&,
+ GlobalSignals) const EXCLUDES(mLock);
FpsRange getSupportedRefreshRateRange() const EXCLUDES(mLock) {
std::lock_guard lock(mLock);
@@ -403,13 +403,8 @@
const std::function<bool(const RefreshRate&)>& shouldAddRefreshRate,
std::vector<const RefreshRate*>* outRefreshRates) REQUIRES(mLock);
- std::optional<RefreshRate> getCachedBestRefreshRate(const std::vector<LayerRequirement>&,
- GlobalSignals,
- GlobalSignals* outSignalsConsidered) const
- REQUIRES(mLock);
-
- RefreshRate getBestRefreshRateLocked(const std::vector<LayerRequirement>&, GlobalSignals,
- GlobalSignals* outSignalsConsidered) const REQUIRES(mLock);
+ std::pair<RefreshRate, GlobalSignals> getBestRefreshRateLocked(
+ const std::vector<LayerRequirement>&, GlobalSignals) 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
@@ -497,14 +492,11 @@
const Config mConfig;
bool mSupportsFrameRateOverrideByContent;
- struct GetBestRefreshRateInvocation {
- std::vector<LayerRequirement> layerRequirements;
- GlobalSignals globalSignals;
- GlobalSignals outSignalsConsidered;
- RefreshRate resultingBestRefreshRate;
+ struct GetBestRefreshRateCache {
+ std::pair<std::vector<LayerRequirement>, GlobalSignals> arguments;
+ std::pair<RefreshRate, GlobalSignals> result;
};
- mutable std::optional<GetBestRefreshRateInvocation> lastBestRefreshRateInvocation
- GUARDED_BY(mLock);
+ mutable std::optional<GetBestRefreshRateCache> mGetBestRefreshRateCache GUARDED_BY(mLock);
// Declare mIdleTimer last to ensure its thread joins before the mutex/callbacks are destroyed.
std::mutex mIdleTimerCallbacksMutex;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index a85e748..665d36982 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -537,18 +537,19 @@
ATRACE_CALL();
- const auto refreshRateConfigs = holdRefreshRateConfigs();
- scheduler::LayerHistory::Summary summary =
- mLayerHistory.summarize(*refreshRateConfigs, systemTime());
- scheduler::RefreshRateConfigs::GlobalSignals consideredSignals;
DisplayModePtr newMode;
+ GlobalSignals consideredSignals;
+
bool frameRateChanged;
bool frameRateOverridesChanged;
+
+ const auto refreshRateConfigs = holdRefreshRateConfigs();
+ LayerHistory::Summary summary = mLayerHistory.summarize(*refreshRateConfigs, systemTime());
{
std::lock_guard<std::mutex> lock(mPolicyLock);
- mPolicy.contentRequirements = summary;
+ mPolicy.contentRequirements = std::move(summary);
- newMode = calculateRefreshRateModeId(&consideredSignals);
+ std::tie(newMode, consideredSignals) = chooseDisplayMode();
frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps());
if (mPolicy.mode == newMode) {
@@ -678,8 +679,7 @@
mVsyncSchedule->dump(out);
}
-bool Scheduler::updateFrameRateOverrides(
- scheduler::RefreshRateConfigs::GlobalSignals consideredSignals, Fps displayRefreshRate) {
+bool Scheduler::updateFrameRateOverrides(GlobalSignals consideredSignals, Fps displayRefreshRate) {
const auto refreshRateConfigs = holdRefreshRateConfigs();
if (!refreshRateConfigs->supportsFrameRateOverrideByContent()) {
return false;
@@ -697,9 +697,11 @@
template <class T>
bool Scheduler::handleTimerStateChanged(T* currentState, T newState) {
DisplayModePtr newMode;
+ GlobalSignals consideredSignals;
+
bool refreshRateChanged = false;
bool frameRateOverridesChanged;
- scheduler::RefreshRateConfigs::GlobalSignals consideredSignals;
+
const auto refreshRateConfigs = holdRefreshRateConfigs();
{
std::lock_guard<std::mutex> lock(mPolicyLock);
@@ -707,7 +709,7 @@
return false;
}
*currentState = newState;
- newMode = calculateRefreshRateModeId(&consideredSignals);
+ std::tie(newMode, consideredSignals) = chooseDisplayMode();
frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps());
if (mPolicy.mode == newMode) {
// We don't need to change the display mode, but we might need to send an event
@@ -733,33 +735,33 @@
return consideredSignals.touch;
}
-DisplayModePtr Scheduler::calculateRefreshRateModeId(
- scheduler::RefreshRateConfigs::GlobalSignals* consideredSignals) {
+auto Scheduler::chooseDisplayMode() -> std::pair<DisplayModePtr, GlobalSignals> {
ATRACE_CALL();
- if (consideredSignals) *consideredSignals = {};
- const auto refreshRateConfigs = holdRefreshRateConfigs();
+ const auto configs = holdRefreshRateConfigs();
+
// 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 (mDisplayPowerTimer &&
(!mPolicy.isDisplayPowerStateNormal || mPolicy.displayPowerTimer == TimerState::Reset)) {
- return refreshRateConfigs->getMaxRefreshRateByPolicy().getMode();
+ constexpr GlobalSignals kNoSignals;
+ return {configs->getMaxRefreshRateByPolicy().getMode(), kNoSignals};
}
- const bool touchActive = mTouchTimer && mPolicy.touch == TouchState::Active;
- const bool idle = mPolicy.idleTimer == TimerState::Expired;
+ const GlobalSignals signals{.touch = mTouchTimer && mPolicy.touch == TouchState::Active,
+ .idle = mPolicy.idleTimer == TimerState::Expired};
- return refreshRateConfigs
- ->getBestRefreshRate(mPolicy.contentRequirements, {.touch = touchActive, .idle = idle},
- consideredSignals)
- .getMode();
+ const auto [refreshRate, consideredSignals] =
+ configs->getBestRefreshRate(mPolicy.contentRequirements, signals);
+
+ return {refreshRate.getMode(), consideredSignals};
}
DisplayModePtr Scheduler::getPreferredDisplayMode() {
std::lock_guard<std::mutex> lock(mPolicyLock);
- // Make sure that the default mode ID is first updated, before returned.
+ // Make sure the stored mode is up to date.
if (mPolicy.mode) {
- mPolicy.mode = calculateRefreshRateModeId();
+ mPolicy.mode = chooseDisplayMode().first;
}
return mPolicy.mode;
}
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index bc9024a..468c4cc 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -269,15 +269,14 @@
void setVsyncPeriod(nsecs_t period);
- // This function checks whether individual features that are affecting the refresh rate
- // selection were initialized, prioritizes them, and calculates the DisplayModeId
- // for the suggested refresh rate.
- DisplayModePtr calculateRefreshRateModeId(
- RefreshRateConfigs::GlobalSignals* consideredSignals = nullptr) REQUIRES(mPolicyLock);
+ using GlobalSignals = RefreshRateConfigs::GlobalSignals;
+
+ // Returns the display mode that fulfills the policy, and the signals that were considered.
+ std::pair<DisplayModePtr, GlobalSignals> chooseDisplayMode() REQUIRES(mPolicyLock);
+
+ bool updateFrameRateOverrides(GlobalSignals, Fps displayRefreshRate) REQUIRES(mPolicyLock);
void dispatchCachedReportedMode() REQUIRES(mPolicyLock) EXCLUDES(mRefreshRateConfigsLock);
- bool updateFrameRateOverrides(RefreshRateConfigs::GlobalSignals, Fps displayRefreshRate)
- REQUIRES(mPolicyLock);
impl::EventThread::ThrottleVsyncCallback makeThrottleVsyncCallback() const
EXCLUDES(mRefreshRateConfigsLock);