diff options
5 files changed, 186 insertions, 5 deletions
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index b062acd948..9746076040 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -190,6 +190,45 @@ struct RefreshRateScore { 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 @@ RefreshRate RefreshRateConfigs::getBestRefreshRate(const std::vector<LayerRequir } }; - std::lock_guard lock(mLock); - int noVoteLayers = 0; int minVoteLayers = 0; int maxVoteLayers = 0; @@ -592,6 +629,11 @@ const RefreshRate& RefreshRateConfigs::getCurrentRefreshRateByPolicyLocked() con 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 @@ RefreshRateConfigs::RefreshRateConfigs(const DisplayModes& modes, DisplayModeId 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 @@ status_t RefreshRateConfigs::setDisplayManagerPolicy(const Policy& policy) { 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 @@ status_t RefreshRateConfigs::setOverridePolicy(const std::optional<Policy>& poli 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 ee89149fd9..342fde0e2a 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -250,6 +250,10 @@ public: 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 @@ private: 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 @@ private: 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 857071c3f1..4b8cbfb621 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -622,9 +622,6 @@ void Scheduler::chooseRefreshRateForContent() { bool frameRateOverridesChanged; { std::lock_guard<std::mutex> lock(mFeatureStateLock); - if (mFeatures.contentRequirements == summary) { - return; - } mFeatures.contentRequirements = summary; newModeId = calculateRefreshRateModeId(&consideredSignals); diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index 7ace70aeef..d04a7d73c7 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -45,9 +45,16 @@ using LayerRequirement = RefreshRateConfigs::LayerRequirement; class RefreshRateConfigsTest : public testing::Test { protected: + using GetBestRefreshRateInvocation = RefreshRateConfigs::GetBestRefreshRateInvocation; + RefreshRateConfigsTest(); ~RefreshRateConfigsTest(); + RefreshRate createRefreshRate(DisplayModePtr displayMode) { + return {displayMode->getId(), displayMode, displayMode->getFps(), + RefreshRate::ConstructorTag(0)}; + } + Fps findClosestKnownFrameRate(const RefreshRateConfigs& refreshRateConfigs, Fps frameRate) { return refreshRateConfigs.findClosestKnownFrameRate(frameRate); } @@ -71,6 +78,19 @@ protected: return *refreshRateConfigs.mMaxSupportedRefreshRate; } + void setLastBestRefreshRateInvocation(RefreshRateConfigs& refreshRateConfigs, + const GetBestRefreshRateInvocation& invocation) { + std::lock_guard lock(refreshRateConfigs.mLock); + refreshRateConfigs.lastBestRefreshRateInvocation.emplace( + GetBestRefreshRateInvocation(invocation)); + } + + std::optional<GetBestRefreshRateInvocation> getLastBestRefreshRateInvocation( + const RefreshRateConfigs& refreshRateConfigs) { + std::lock_guard lock(refreshRateConfigs.mLock); + return refreshRateConfigs.lastBestRefreshRateInvocation; + } + // Test config IDs static inline const DisplayModeId HWC_CONFIG_ID_60 = DisplayModeId(0); static inline const DisplayModeId HWC_CONFIG_ID_90 = DisplayModeId(1); @@ -1752,6 +1772,78 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExactEnableFrameRateOv refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); } +TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ReadsCached) { + using GlobalSignals = RefreshRateConfigs::GlobalSignals; + + auto refreshRateConfigs = + std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device, + /*currentConfigId=*/HWC_CONFIG_ID_60); + + setLastBestRefreshRateInvocation(*refreshRateConfigs, + GetBestRefreshRateInvocation{.layerRequirements = std::vector< + LayerRequirement>(), + .globalSignals = {.touch = true, + .idle = true}, + .outSignalsConsidered = + {.touch = true, + .idle = false}, + .resultingBestRefreshRate = + createRefreshRate( + mConfig90)}); + + EXPECT_EQ(createRefreshRate(mConfig90), + refreshRateConfigs->getBestRefreshRate(std::vector<LayerRequirement>(), + {.touch = true, .idle = true})); + + const GlobalSignals cachedSignalsConsidered{.touch = true, .idle = false}; + setLastBestRefreshRateInvocation(*refreshRateConfigs, + GetBestRefreshRateInvocation{.layerRequirements = std::vector< + LayerRequirement>(), + .globalSignals = {.touch = true, + .idle = true}, + .outSignalsConsidered = + cachedSignalsConsidered, + .resultingBestRefreshRate = + createRefreshRate( + mConfig30)}); + + GlobalSignals signalsConsidered; + EXPECT_EQ(createRefreshRate(mConfig30), + refreshRateConfigs->getBestRefreshRate(std::vector<LayerRequirement>(), + {.touch = true, .idle = true}, + &signalsConsidered)); + + EXPECT_EQ(cachedSignalsConsidered, signalsConsidered); +} + +TEST_F(RefreshRateConfigsTest, getBestRefreshRate_WritesCache) { + using GlobalSignals = RefreshRateConfigs::GlobalSignals; + + auto refreshRateConfigs = + std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device, + /*currentConfigId=*/HWC_CONFIG_ID_60); + ASSERT_FALSE(getLastBestRefreshRateInvocation(*refreshRateConfigs).has_value()); + + GlobalSignals globalSignals{.touch = true, .idle = true}; + auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}, + LayerRequirement{.weight = 0.5f}}; + const auto lastResult = + refreshRateConfigs->getBestRefreshRate(layers, globalSignals, + /* outSignalsConsidered */ nullptr); + + const auto lastInvocation = getLastBestRefreshRateInvocation(*refreshRateConfigs); + + ASSERT_TRUE(lastInvocation.has_value()); + ASSERT_EQ(layers, lastInvocation->layerRequirements); + ASSERT_EQ(globalSignals, lastInvocation->globalSignals); + ASSERT_EQ(lastResult, lastInvocation->resultingBestRefreshRate); + + // outSignalsConsidered needs to be populated even tho earlier we gave nullptr + // to getBestRefreshRate() + GlobalSignals detaultSignals; + ASSERT_FALSE(detaultSignals == lastInvocation->outSignalsConsidered); +} + TEST_F(RefreshRateConfigsTest, testComparisonOperator) { EXPECT_TRUE(mExpected60Config < mExpected90Config); EXPECT_FALSE(mExpected60Config < mExpected60Config); diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index 8ad8ea4299..423d0ccbff 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -220,4 +220,25 @@ TEST_F(SchedulerTest, calculateExtraBufferCount) { EXPECT_EQ(0, mFlinger.calculateExtraBufferCount(Fps(60), 10ms)); } +MATCHER(Is120Hz, "") { + return arg.getFps().equalsWithMargin(Fps(120.f)); +} + +TEST_F(SchedulerTest, chooseRefreshRateForContentSelectsMaxRefreshRate) { + mConfigs.updateDisplayModes({mode60, mode120}, /* activeMode */ mode60->getId()); + + sp<mock::MockLayer> layer = sp<mock::MockLayer>::make(mFlinger.flinger()); + + mScheduler->recordLayerHistory(layer.get(), 0, LayerHistory::LayerUpdateType::Buffer); + + constexpr bool kPowerStateNormal = true; + mScheduler->setDisplayPowerState(kPowerStateNormal); + + constexpr uint32_t kDisplayArea = 999'999; + mScheduler->onPrimaryDisplayAreaChanged(kDisplayArea); + + EXPECT_CALL(mSchedulerCallback, changeRefreshRate(Is120Hz(), _)).Times(1); + mScheduler->chooseRefreshRateForContent(); +} + } // namespace android |