From d82e0f03d84b6c19484b4ae0ecfcedeb32724427 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Wed, 26 Oct 2022 15:23:04 -0400 Subject: SF: Rename RefreshRateConfigs "Configs" is vague and overloaded, and collections thereof cannot simply pluralize the name. Also, update the stale class comment. Bug: 241285191 Test: Build Change-Id: I3b6d2259dcaa390f44c07caa07c05361c6cb428b --- services/surfaceflinger/Android.bp | 2 +- services/surfaceflinger/DisplayDevice.cpp | 18 +- services/surfaceflinger/DisplayDevice.h | 19 +- services/surfaceflinger/Layer.cpp | 6 +- services/surfaceflinger/Scheduler/LayerHistory.cpp | 4 +- services/surfaceflinger/Scheduler/LayerHistory.h | 8 +- services/surfaceflinger/Scheduler/LayerInfo.cpp | 10 +- services/surfaceflinger/Scheduler/LayerInfo.h | 6 +- .../Scheduler/RefreshRateConfigs.cpp | 1152 ---------- .../surfaceflinger/Scheduler/RefreshRateConfigs.h | 475 ---- .../Scheduler/RefreshRateSelector.cpp | 1155 ++++++++++ .../surfaceflinger/Scheduler/RefreshRateSelector.h | 473 ++++ services/surfaceflinger/Scheduler/Scheduler.cpp | 88 +- services/surfaceflinger/Scheduler/Scheduler.h | 40 +- .../surfaceflinger/Scheduler/VSyncPredictor.cpp | 4 +- services/surfaceflinger/SurfaceFlinger.cpp | 85 +- services/surfaceflinger/SurfaceFlinger.h | 10 +- services/surfaceflinger/SurfaceFlingerFactory.h | 1 - .../fuzzer/surfaceflinger_fuzzers_utils.h | 27 +- .../fuzzer/surfaceflinger_scheduler_fuzzer.cpp | 63 +- .../fuzzer/surfaceflinger_scheduler_fuzzer.h | 1 - services/surfaceflinger/tests/unittests/Android.bp | 2 +- .../tests/unittests/LayerHistoryTest.cpp | 22 +- .../tests/unittests/RefreshRateConfigsTest.cpp | 2427 -------------------- .../tests/unittests/RefreshRateSelectorTest.cpp | 2421 +++++++++++++++++++ .../tests/unittests/SchedulerTest.cpp | 24 +- .../tests/unittests/SetFrameRateTest.cpp | 4 +- .../SurfaceFlinger_DisplayModeSwitching.cpp | 12 +- .../tests/unittests/TestableScheduler.h | 14 +- .../tests/unittests/TestableSurfaceFlinger.h | 41 +- 30 files changed, 4303 insertions(+), 4311 deletions(-) delete mode 100644 services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp delete mode 100644 services/surfaceflinger/Scheduler/RefreshRateConfigs.h create mode 100644 services/surfaceflinger/Scheduler/RefreshRateSelector.cpp create mode 100644 services/surfaceflinger/Scheduler/RefreshRateSelector.h delete mode 100644 services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp create mode 100644 services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp (limited to 'services/surfaceflinger') diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index b65f1b48e3..cb54cad9b1 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -180,7 +180,7 @@ filegroup { "Scheduler/LayerHistory.cpp", "Scheduler/LayerInfo.cpp", "Scheduler/MessageQueue.cpp", - "Scheduler/RefreshRateConfigs.cpp", + "Scheduler/RefreshRateSelector.cpp", "Scheduler/Scheduler.cpp", "Scheduler/VSyncDispatchTimerQueue.cpp", "Scheduler/VSyncPredictor.cpp", diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index c63d57f6ee..18ddfbca6c 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -69,7 +69,7 @@ DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs& args) mActiveModeFPSHwcTrace("ActiveModeFPS_HWC -" + to_string(getId())), mPhysicalOrientation(args.physicalOrientation), mIsPrimary(args.isPrimary), - mRefreshRateConfigs(std::move(args.refreshRateConfigs)) { + mRefreshRateSelector(std::move(args.refreshRateSelector)) { mCompositionDisplay->editState().isSecure = args.isSecure; mCompositionDisplay->createRenderSurface( compositionengine::RenderSurfaceCreationArgsBuilder() @@ -200,7 +200,7 @@ void DisplayDevice::setActiveMode(DisplayModeId modeId, const display::DisplaySn ATRACE_INT(mActiveModeFPSTrace.c_str(), fps.getIntValue()); - mRefreshRateConfigs->setActiveModeId(modeId); + mRefreshRateSelector->setActiveModeId(modeId); if (mRefreshRateOverlay) { mRefreshRateOverlay->changeRefreshRate(fps); @@ -234,7 +234,7 @@ nsecs_t DisplayDevice::getVsyncPeriodFromHWC() const { return vsyncPeriod; } - return refreshRateConfigs().getActiveModePtr()->getVsyncPeriod(); + return refreshRateSelector().getActiveModePtr()->getVsyncPeriod(); } ui::Dataspace DisplayDevice::getCompositionDataSpace() const { @@ -335,8 +335,8 @@ void DisplayDevice::dump(utils::Dumper& dumper) const { utils::Dumper::Indent indent(dumper); dumper.dump("powerMode"sv, mPowerMode); - if (mRefreshRateConfigs) { - mRefreshRateConfigs->dump(dumper); + if (mRefreshRateSelector) { + mRefreshRateSelector->dump(dumper); } } @@ -430,7 +430,7 @@ void DisplayDevice::enableRefreshRateOverlay(bool enable, bool showSpinnner) { return; } - const auto fpsRange = mRefreshRateConfigs->getSupportedRefreshRateRange(); + const auto fpsRange = mRefreshRateSelector->getSupportedRefreshRateRange(); mRefreshRateOverlay = std::make_unique(fpsRange, showSpinnner); mRefreshRateOverlay->setLayerStack(getLayerStack()); mRefreshRateOverlay->setViewport(getSize()); @@ -439,9 +439,9 @@ void DisplayDevice::enableRefreshRateOverlay(bool enable, bool showSpinnner) { bool DisplayDevice::onKernelTimerChanged(std::optional desiredModeId, bool timerExpired) { - if (mRefreshRateConfigs && mRefreshRateOverlay) { + if (mRefreshRateSelector && mRefreshRateOverlay) { const auto newRefreshRate = - mRefreshRateConfigs->onKernelTimerChanged(desiredModeId, timerExpired); + mRefreshRateSelector->onKernelTimerChanged(desiredModeId, timerExpired); if (newRefreshRate) { mRefreshRateOverlay->changeRefreshRate(*newRefreshRate); return true; @@ -475,7 +475,7 @@ bool DisplayDevice::setDesiredActiveMode(const ActiveModeInfo& info) { } // Check if we are already at the desired mode - if (refreshRateConfigs().getActiveModePtr()->getId() == info.mode->getId()) { + if (refreshRateSelector().getActiveModePtr()->getId() == info.mode->getId()) { return false; } diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 7abb94b84f..6c848bb100 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -45,7 +45,7 @@ #include "DisplayHardware/DisplayMode.h" #include "DisplayHardware/Hal.h" #include "DisplayHardware/PowerAdvisor.h" -#include "Scheduler/RefreshRateConfigs.h" +#include "Scheduler/RefreshRateSelector.h" #include "ThreadContext.h" #include "TracedOrdinal.h" #include "Utils/Dumper.h" @@ -219,7 +219,7 @@ public: } const DisplayMode& getActiveMode() const REQUIRES(kMainThreadContext) { - return mRefreshRateConfigs->getActiveMode(); + return mRefreshRateSelector->getActiveMode(); } // Precondition: DisplaySnapshot must contain a mode with DisplayModeId. @@ -230,14 +230,11 @@ public: hal::VsyncPeriodChangeTimeline* outTimeline) REQUIRES(kMainThreadContext); - // Returns the refresh rate configs for this display. - scheduler::RefreshRateConfigs& refreshRateConfigs() const { return *mRefreshRateConfigs; } + scheduler::RefreshRateSelector& refreshRateSelector() const { return *mRefreshRateSelector; } - // Returns a shared pointer to the refresh rate configs for this display. - // Clients can store this refresh rate configs and use it even if the DisplayDevice - // is destroyed. - std::shared_ptr holdRefreshRateConfigs() const { - return mRefreshRateConfigs; + // Extends the lifetime of the RefreshRateSelector, so it can outlive this DisplayDevice. + std::shared_ptr holdRefreshRateSelector() const { + return mRefreshRateSelector; } // Enables an overlay to be displayed with the current refresh rate @@ -287,7 +284,7 @@ private: std::vector mOverrideHdrTypes; - std::shared_ptr mRefreshRateConfigs; + std::shared_ptr mRefreshRateSelector; std::unique_ptr mRefreshRateOverlay; mutable std::mutex mActiveModeLock; @@ -337,7 +334,7 @@ struct DisplayDeviceCreationArgs { HWComposer& hwComposer; const wp displayToken; const std::shared_ptr compositionDisplay; - std::shared_ptr refreshRateConfigs; + std::shared_ptr refreshRateSelector; int32_t sequenceId{0}; bool isSecure{false}; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index b47188fea4..60a2ee7ef5 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -195,7 +195,7 @@ Layer::Layer(const LayerCreationArgs& args) } mFrameTracker.setDisplayRefreshPeriod( - args.flinger->mScheduler->getVsyncPeriodFromRefreshRateConfigs()); + args.flinger->mScheduler->getVsyncPeriodFromRefreshRateSelector()); mOwnerUid = args.ownerUid; mOwnerPid = args.ownerPid; @@ -1128,7 +1128,7 @@ bool Layer::propagateFrameRateForLayerTree(FrameRate parentFrameRate, bool* tran // We return whether this layer ot its children has a vote. We ignore ExactOrMultiple votes for // the same reason we are allowing touch boost for those layers. See - // RefreshRateConfigs::getBestRefreshRate for more details. + // RefreshRateSelector::rankRefreshRates for details. const auto layerVotedWithDefaultCompatibility = frameRate.rate.isValid() && frameRate.type == FrameRateCompatibility::Default; const auto layerVotedWithNoVote = frameRate.type == FrameRateCompatibility::NoVote; @@ -3613,7 +3613,7 @@ void Layer::onPostComposition(const DisplayDevice* display, } if (display) { - const Fps refreshRate = display->refreshRateConfigs().getActiveModePtr()->getFps(); + const Fps refreshRate = display->refreshRateSelector().getActiveModePtr()->getFps(); const std::optional renderRate = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid()); diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index ae111c3d45..b884dc873d 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -164,7 +164,7 @@ void LayerHistory::setDefaultFrameRateCompatibility(Layer* layer, bool contentDe getVoteType(layer->getDefaultFrameRateCompatibility(), contentDetectionEnabled)); } -auto LayerHistory::summarize(const RefreshRateConfigs& configs, nsecs_t now) -> Summary { +auto LayerHistory::summarize(const RefreshRateSelector& selector, nsecs_t now) -> Summary { Summary summary; std::lock_guard lock(mLock); @@ -178,7 +178,7 @@ auto LayerHistory::summarize(const RefreshRateConfigs& configs, nsecs_t now) -> ALOGV("%s has priority: %d %s focused", info->getName().c_str(), frameRateSelectionPriority, layerFocused ? "" : "not"); - const auto vote = info->getRefreshRateVote(configs, now); + const auto vote = info->getRefreshRateVote(selector, now); // Skip NoVote layer as those don't have any requirements if (vote.type == LayerVoteType::NoVote) { continue; diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h index 12bec8dfc1..5022906ff9 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.h +++ b/services/surfaceflinger/Scheduler/LayerHistory.h @@ -27,7 +27,7 @@ #include #include -#include "RefreshRateConfigs.h" +#include "RefreshRateSelector.h" namespace android { @@ -39,7 +39,7 @@ class LayerInfo; class LayerHistory { public: - using LayerVoteType = RefreshRateConfigs::LayerVoteType; + using LayerVoteType = RefreshRateSelector::LayerVoteType; LayerHistory(); ~LayerHistory(); @@ -67,10 +67,10 @@ public: // does not set a preference for refresh rate. void setDefaultFrameRateCompatibility(Layer*, bool contentDetectionEnabled); - using Summary = std::vector; + using Summary = std::vector; // Rebuilds sets of active/inactive layers, and accumulates stats for active layers. - Summary summarize(const RefreshRateConfigs&, nsecs_t now); + Summary summarize(const RefreshRateSelector&, nsecs_t now); void clear(); diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp index 943615c45c..7247e4b260 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.cpp +++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp @@ -187,8 +187,8 @@ std::optional LayerInfo::calculateAverageFrameTime() const { return static_cast(averageFrameTime); } -std::optional LayerInfo::calculateRefreshRateIfPossible( - const RefreshRateConfigs& refreshRateConfigs, nsecs_t now) { +std::optional LayerInfo::calculateRefreshRateIfPossible(const RefreshRateSelector& selector, + nsecs_t now) { static constexpr float MARGIN = 1.0f; // 1Hz if (!hasEnoughDataForHeuristic()) { ALOGV("Not enough data"); @@ -199,7 +199,7 @@ std::optional LayerInfo::calculateRefreshRateIfPossible( const auto refreshRate = Fps::fromPeriodNsecs(*averageFrameTime); const bool refreshRateConsistent = mRefreshRateHistory.add(refreshRate, now); if (refreshRateConsistent) { - const auto knownRefreshRate = refreshRateConfigs.findClosestKnownFrameRate(refreshRate); + const auto knownRefreshRate = selector.findClosestKnownFrameRate(refreshRate); using fps_approx_ops::operator!=; // To avoid oscillation, use the last calculated refresh rate if it is close enough. @@ -222,7 +222,7 @@ std::optional LayerInfo::calculateRefreshRateIfPossible( : std::nullopt; } -LayerInfo::LayerVote LayerInfo::getRefreshRateVote(const RefreshRateConfigs& refreshRateConfigs, +LayerInfo::LayerVote LayerInfo::getRefreshRateVote(const RefreshRateSelector& selector, nsecs_t now) { if (mLayerVote.type != LayerHistory::LayerVoteType::Heuristic) { ALOGV("%s voted %d ", mName.c_str(), static_cast(mLayerVote.type)); @@ -250,7 +250,7 @@ LayerInfo::LayerVote LayerInfo::getRefreshRateVote(const RefreshRateConfigs& ref clearHistory(now); } - auto refreshRate = calculateRefreshRateIfPossible(refreshRateConfigs, now); + auto refreshRate = calculateRefreshRateIfPossible(selector, now); if (refreshRate.has_value()) { ALOGV("%s calculated refresh rate: %s", mName.c_str(), to_string(*refreshRate).c_str()); return {LayerHistory::LayerVoteType::Heuristic, refreshRate.value()}; diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h index 28cb24a64f..a5ffbbecb5 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.h +++ b/services/surfaceflinger/Scheduler/LayerInfo.h @@ -28,7 +28,7 @@ #include #include "LayerHistory.h" -#include "RefreshRateConfigs.h" +#include "RefreshRateSelector.h" namespace android { @@ -162,7 +162,7 @@ public: uid_t getOwnerUid() const { return mOwnerUid; } - LayerVote getRefreshRateVote(const RefreshRateConfigs&, nsecs_t now); + LayerVote getRefreshRateVote(const RefreshRateSelector&, nsecs_t now); // Return the last updated time. If the present time is farther in the future than the // updated time, the updated time is the present time. @@ -261,7 +261,7 @@ private: bool isFrequent(nsecs_t now) const; bool isAnimating(nsecs_t now) const; bool hasEnoughDataForHeuristic() const; - std::optional calculateRefreshRateIfPossible(const RefreshRateConfigs&, nsecs_t now); + std::optional calculateRefreshRateIfPossible(const RefreshRateSelector&, nsecs_t now); std::optional calculateAverageFrameTime() const; bool isFrameTimeValid(const FrameTimeData&) const; diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp deleted file mode 100644 index 39850c7e1e..0000000000 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ /dev/null @@ -1,1152 +0,0 @@ -/* - * Copyright 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// #define LOG_NDEBUG 0 -#define ATRACE_TAG ATRACE_TAG_GRAPHICS - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wextra" - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "../SurfaceFlingerProperties.h" -#include "RefreshRateConfigs.h" - -#undef LOG_TAG -#define LOG_TAG "RefreshRateConfigs" - -namespace android::scheduler { -namespace { - -struct RefreshRateScore { - DisplayModeIterator modeIt; - float overallScore; - struct { - float modeBelowThreshold; - float modeAboveThreshold; - } fixedRateBelowThresholdLayersScore; -}; - -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, - ftl::enum_string(layer.seamlessness).c_str(), - to_string(layer.desiredRefreshRate).c_str()); -} - -std::vector constructKnownFrameRates(const DisplayModes& modes) { - std::vector knownFrameRates = {24_Hz, 30_Hz, 45_Hz, 60_Hz, 72_Hz}; - knownFrameRates.reserve(knownFrameRates.size() + modes.size()); - - // Add all supported refresh rates. - for (const auto& [id, mode] : modes) { - knownFrameRates.push_back(mode->getFps()); - } - - // Sort and remove duplicates. - std::sort(knownFrameRates.begin(), knownFrameRates.end(), isStrictlyLess); - knownFrameRates.erase(std::unique(knownFrameRates.begin(), knownFrameRates.end(), - isApproxEqual), - knownFrameRates.end()); - return knownFrameRates; -} - -// The Filter is a `bool(const DisplayMode&)` predicate. -template -std::vector sortByRefreshRate(const DisplayModes& modes, Filter&& filter) { - std::vector sortedModes; - sortedModes.reserve(modes.size()); - - for (auto it = modes.begin(); it != modes.end(); ++it) { - const auto& [id, mode] = *it; - - if (filter(*mode)) { - ALOGV("%s: including mode %d", __func__, id.value()); - sortedModes.push_back(it); - } - } - - std::sort(sortedModes.begin(), sortedModes.end(), [](auto it1, auto it2) { - const auto& mode1 = it1->second; - const auto& mode2 = it2->second; - - if (mode1->getVsyncPeriod() == mode2->getVsyncPeriod()) { - return mode1->getGroup() > mode2->getGroup(); - } - - return mode1->getVsyncPeriod() > mode2->getVsyncPeriod(); - }); - - return sortedModes; -} - -bool canModesSupportFrameRateOverride(const std::vector& sortedModes) { - for (const auto it1 : sortedModes) { - const auto& mode1 = it1->second; - for (const auto it2 : sortedModes) { - const auto& mode2 = it2->second; - - if (RefreshRateConfigs::getFrameRateDivisor(mode1->getFps(), mode2->getFps()) >= 2) { - return true; - } - } - } - return false; -} - -std::string toString(const RefreshRateConfigs::PolicyVariant& policy) { - using namespace std::string_literals; - - return ftl::match( - policy, - [](const RefreshRateConfigs::DisplayManagerPolicy& policy) { - return "DisplayManagerPolicy"s + policy.toString(); - }, - [](const RefreshRateConfigs::OverridePolicy& policy) { - return "OverridePolicy"s + policy.toString(); - }, - [](RefreshRateConfigs::NoOverridePolicy) { return "NoOverridePolicy"s; }); -} - -} // namespace - -struct RefreshRateConfigs::RefreshRateScoreComparator { - bool operator()(const RefreshRateScore& lhs, const RefreshRateScore& rhs) const { - const auto& [modeIt, overallScore, _] = lhs; - - std::string name = to_string(modeIt->second->getFps()); - ALOGV("%s sorting scores %.2f", name.c_str(), overallScore); - - ATRACE_INT(name.c_str(), static_cast(std::round(overallScore * 100))); - - if (!ScoredRefreshRate::scoresEqual(overallScore, rhs.overallScore)) { - return overallScore > rhs.overallScore; - } - - // If overallScore tie we will pick the higher refresh rate if - // high refresh rate is the priority else the lower refresh rate. - if (refreshRateOrder == RefreshRateOrder::Descending) { - using fps_approx_ops::operator>; - return modeIt->second->getFps() > rhs.modeIt->second->getFps(); - } else { - using fps_approx_ops::operator<; - return modeIt->second->getFps() < rhs.modeIt->second->getFps(); - } - } - - const RefreshRateOrder refreshRateOrder; -}; - -std::string RefreshRateConfigs::Policy::toString() const { - return base::StringPrintf("{defaultModeId=%d, allowGroupSwitching=%s" - ", primaryRange=%s, appRequestRange=%s}", - defaultMode.value(), allowGroupSwitching ? "true" : "false", - to_string(primaryRange).c_str(), to_string(appRequestRange).c_str()); -} - -std::pair RefreshRateConfigs::getDisplayFrames(nsecs_t layerPeriod, - nsecs_t displayPeriod) const { - auto [quotient, remainder] = std::div(layerPeriod, displayPeriod); - if (remainder <= MARGIN_FOR_PERIOD_CALCULATION || - std::abs(remainder - displayPeriod) <= MARGIN_FOR_PERIOD_CALCULATION) { - quotient++; - remainder = 0; - } - - return {quotient, remainder}; -} - -float RefreshRateConfigs::calculateNonExactMatchingLayerScoreLocked(const LayerRequirement& layer, - Fps refreshRate) const { - constexpr float kScoreForFractionalPairs = .8f; - - const auto displayPeriod = refreshRate.getPeriodNsecs(); - const auto layerPeriod = layer.desiredRefreshRate.getPeriodNsecs(); - if (layer.vote == LayerVoteType::ExplicitDefault) { - // Find the actual rate the layer will render, assuming - // that layerPeriod is the minimal period to render a frame. - // For example if layerPeriod is 20ms and displayPeriod is 16ms, - // then the actualLayerPeriod will be 32ms, because it is the - // smallest multiple of the display period which is >= layerPeriod. - auto actualLayerPeriod = displayPeriod; - int multiplier = 1; - while (layerPeriod > actualLayerPeriod + MARGIN_FOR_PERIOD_CALCULATION) { - multiplier++; - actualLayerPeriod = displayPeriod * multiplier; - } - - // Because of the threshold we used above it's possible that score is slightly - // above 1. - return std::min(1.0f, - static_cast(layerPeriod) / static_cast(actualLayerPeriod)); - } - - if (layer.vote == LayerVoteType::ExplicitExactOrMultiple || - layer.vote == LayerVoteType::Heuristic) { - if (isFractionalPairOrMultiple(refreshRate, layer.desiredRefreshRate)) { - return kScoreForFractionalPairs; - } - - // Calculate how many display vsyncs we need to present a single frame for this - // layer - const auto [displayFramesQuotient, displayFramesRemainder] = - getDisplayFrames(layerPeriod, displayPeriod); - static constexpr size_t MAX_FRAMES_TO_FIT = 10; // Stop calculating when score < 0.1 - if (displayFramesRemainder == 0) { - // Layer desired refresh rate matches the display rate. - return 1.0f; - } - - if (displayFramesQuotient == 0) { - // Layer desired refresh rate is higher than the display rate. - return (static_cast(layerPeriod) / static_cast(displayPeriod)) * - (1.0f / (MAX_FRAMES_TO_FIT + 1)); - } - - // Layer desired refresh rate is lower than the display rate. Check how well it fits - // the cadence. - auto diff = std::abs(displayFramesRemainder - (displayPeriod - displayFramesRemainder)); - int iter = 2; - while (diff > MARGIN_FOR_PERIOD_CALCULATION && iter < MAX_FRAMES_TO_FIT) { - diff = diff - (displayPeriod - diff); - iter++; - } - - return (1.0f / iter); - } - - return 0; -} - -float RefreshRateConfigs::calculateRefreshRateScoreForFps(Fps refreshRate) const { - const float ratio = - refreshRate.getValue() / mAppRequestRefreshRates.back()->second->getFps().getValue(); - // Use ratio^2 to get a lower score the more we get further from peak - return ratio * ratio; -} - -float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& layer, Fps refreshRate, - bool isSeamlessSwitch) const { - // Slightly prefer seamless switches. - constexpr float kSeamedSwitchPenalty = 0.95f; - const float seamlessness = isSeamlessSwitch ? 1.0f : kSeamedSwitchPenalty; - - // If the layer wants Max, give higher score to the higher refresh rate - if (layer.vote == LayerVoteType::Max) { - return calculateRefreshRateScoreForFps(refreshRate); - } - - if (layer.vote == LayerVoteType::ExplicitExact) { - const int divisor = getFrameRateDivisor(refreshRate, layer.desiredRefreshRate); - if (mSupportsFrameRateOverrideByContent) { - // Since we support frame rate override, allow refresh rates which are - // multiples of the layer's request, as those apps would be throttled - // down to run at the desired refresh rate. - return divisor > 0; - } - - return divisor == 1; - } - - // If the layer frame rate is a divisor of the refresh rate it should score - // the highest score. - if (getFrameRateDivisor(refreshRate, layer.desiredRefreshRate) > 0) { - return 1.0f * seamlessness; - } - - // The layer frame rate is not a divisor of the refresh rate, - // there is a small penalty attached to the score to favor the frame rates - // the exactly matches the display refresh rate or a multiple. - constexpr float kNonExactMatchingPenalty = 0.95f; - return calculateNonExactMatchingLayerScoreLocked(layer, refreshRate) * seamlessness * - kNonExactMatchingPenalty; -} - -auto RefreshRateConfigs::getRankedRefreshRates(const std::vector& layers, - GlobalSignals signals) const -> RankedRefreshRates { - std::lock_guard lock(mLock); - - if (mGetRankedRefreshRatesCache && - mGetRankedRefreshRatesCache->arguments == std::make_pair(layers, signals)) { - return mGetRankedRefreshRatesCache->result; - } - - const auto result = getRankedRefreshRatesLocked(layers, signals); - mGetRankedRefreshRatesCache = GetRankedRefreshRatesCache{{layers, signals}, result}; - return result; -} - -auto RefreshRateConfigs::getRankedRefreshRatesLocked(const std::vector& layers, - GlobalSignals signals) const - -> RankedRefreshRates { - using namespace fps_approx_ops; - ATRACE_CALL(); - ALOGV("%s: %zu layers", __func__, layers.size()); - - const auto& activeMode = *getActiveModeItLocked()->second; - - // Keep the display at max refresh rate for the duration of powering on the display. - if (signals.powerOnImminent) { - ALOGV("Power On Imminent"); - return {rankRefreshRates(activeMode.getGroup(), RefreshRateOrder::Descending), - GlobalSignals{.powerOnImminent = true}}; - } - - int noVoteLayers = 0; - int minVoteLayers = 0; - int maxVoteLayers = 0; - int explicitDefaultVoteLayers = 0; - int explicitExactOrMultipleVoteLayers = 0; - int explicitExact = 0; - int seamedFocusedLayers = 0; - - for (const auto& layer : layers) { - switch (layer.vote) { - case LayerVoteType::NoVote: - noVoteLayers++; - break; - case LayerVoteType::Min: - minVoteLayers++; - break; - case LayerVoteType::Max: - maxVoteLayers++; - break; - case LayerVoteType::ExplicitDefault: - explicitDefaultVoteLayers++; - break; - case LayerVoteType::ExplicitExactOrMultiple: - explicitExactOrMultipleVoteLayers++; - break; - case LayerVoteType::ExplicitExact: - explicitExact++; - break; - case LayerVoteType::Heuristic: - break; - } - - if (layer.seamlessness == Seamlessness::SeamedAndSeamless && layer.focused) { - seamedFocusedLayers++; - } - } - - const bool hasExplicitVoteLayers = explicitDefaultVoteLayers > 0 || - explicitExactOrMultipleVoteLayers > 0 || explicitExact > 0; - - const Policy* policy = getCurrentPolicyLocked(); - const auto& defaultMode = mDisplayModes.get(policy->defaultMode)->get(); - - // If the default mode group is different from the group of current mode, - // this means a layer requesting a seamed mode switch just disappeared and - // we should switch back to the default group. - // However if a seamed layer is still present we anchor around the group - // of the current mode, in order to prevent unnecessary seamed mode switches - // (e.g. when pausing a video playback). - const auto anchorGroup = - seamedFocusedLayers > 0 ? activeMode.getGroup() : defaultMode->getGroup(); - - // 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 (signals.touch && !hasExplicitVoteLayers) { - ALOGV("Touch Boost"); - return {rankRefreshRates(anchorGroup, RefreshRateOrder::Descending), - GlobalSignals{.touch = true}}; - } - - // If the primary range consists of a single refresh rate then we can only - // move out the of range if layers explicitly request a different refresh - // rate. - const bool primaryRangeIsSingleRate = - isApproxEqual(policy->primaryRange.min, policy->primaryRange.max); - - if (!signals.touch && signals.idle && !(primaryRangeIsSingleRate && hasExplicitVoteLayers)) { - ALOGV("Idle"); - return {rankRefreshRates(activeMode.getGroup(), RefreshRateOrder::Ascending), - GlobalSignals{.idle = true}}; - } - - if (layers.empty() || noVoteLayers == layers.size()) { - ALOGV("No layers with votes"); - return {rankRefreshRates(anchorGroup, RefreshRateOrder::Descending), kNoSignals}; - } - - // Only if all layers want Min we should return Min - if (noVoteLayers + minVoteLayers == layers.size()) { - ALOGV("All layers Min"); - return {rankRefreshRates(activeMode.getGroup(), RefreshRateOrder::Ascending), kNoSignals}; - } - - // Find the best refresh rate based on score - std::vector scores; - scores.reserve(mAppRequestRefreshRates.size()); - - for (const DisplayModeIterator modeIt : mAppRequestRefreshRates) { - scores.emplace_back(RefreshRateScore{modeIt, 0.0f}); - } - - for (const auto& layer : layers) { - ALOGV("Calculating score for %s (%s, weight %.2f, desired %.2f) ", layer.name.c_str(), - ftl::enum_string(layer.vote).c_str(), layer.weight, - layer.desiredRefreshRate.getValue()); - if (layer.vote == LayerVoteType::NoVote || layer.vote == LayerVoteType::Min) { - continue; - } - - const auto weight = layer.weight; - - for (auto& [modeIt, overallScore, fixedRateBelowThresholdLayersScore] : scores) { - const auto& [id, mode] = *modeIt; - const bool isSeamlessSwitch = mode->getGroup() == activeMode.getGroup(); - - if (layer.seamlessness == Seamlessness::OnlySeamless && !isSeamlessSwitch) { - ALOGV("%s ignores %s to avoid non-seamless switch. Current mode = %s", - formatLayerInfo(layer, weight).c_str(), to_string(*mode).c_str(), - to_string(activeMode).c_str()); - continue; - } - - if (layer.seamlessness == Seamlessness::SeamedAndSeamless && !isSeamlessSwitch && - !layer.focused) { - ALOGV("%s ignores %s because it's not focused and the switch is going to be seamed." - " Current mode = %s", - formatLayerInfo(layer, weight).c_str(), to_string(*mode).c_str(), - to_string(activeMode).c_str()); - continue; - } - - // Layers with default seamlessness vote for the current mode group if - // there are layers with seamlessness=SeamedAndSeamless and for the default - // mode group otherwise. In second case, if the current mode group is different - // from the default, this means a layer with seamlessness=SeamedAndSeamless has just - // disappeared. - const bool isInPolicyForDefault = mode->getGroup() == anchorGroup; - if (layer.seamlessness == Seamlessness::Default && !isInPolicyForDefault) { - ALOGV("%s ignores %s. Current mode = %s", formatLayerInfo(layer, weight).c_str(), - to_string(*mode).c_str(), to_string(activeMode).c_str()); - continue; - } - - const bool inPrimaryRange = policy->primaryRange.includes(mode->getFps()); - if ((primaryRangeIsSingleRate || !inPrimaryRange) && - !(layer.focused && - (layer.vote == LayerVoteType::ExplicitDefault || - layer.vote == LayerVoteType::ExplicitExact))) { - // Only focused layers with ExplicitDefault frame rate settings are allowed to score - // refresh rates outside the primary range. - continue; - } - - const float layerScore = - calculateLayerScoreLocked(layer, mode->getFps(), isSeamlessSwitch); - const float weightedLayerScore = weight * layerScore; - - // Layer with fixed source has a special consideration which depends on the - // mConfig.frameRateMultipleThreshold. We don't want these layers to score - // refresh rates above the threshold, but we also don't want to favor the lower - // ones by having a greater number of layers scoring them. Instead, we calculate - // the score independently for these layers and later decide which - // refresh rates to add it. For example, desired 24 fps with 120 Hz threshold should not - // score 120 Hz, but desired 60 fps should contribute to the score. - const bool fixedSourceLayer = [](LayerVoteType vote) { - switch (vote) { - case LayerVoteType::ExplicitExactOrMultiple: - case LayerVoteType::Heuristic: - return true; - case LayerVoteType::NoVote: - case LayerVoteType::Min: - case LayerVoteType::Max: - case LayerVoteType::ExplicitDefault: - case LayerVoteType::ExplicitExact: - return false; - } - }(layer.vote); - const bool layerBelowThreshold = mConfig.frameRateMultipleThreshold != 0 && - layer.desiredRefreshRate < - Fps::fromValue(mConfig.frameRateMultipleThreshold / 2); - if (fixedSourceLayer && layerBelowThreshold) { - const bool modeAboveThreshold = - mode->getFps() >= Fps::fromValue(mConfig.frameRateMultipleThreshold); - if (modeAboveThreshold) { - ALOGV("%s gives %s fixed source (above threshold) score of %.4f", - formatLayerInfo(layer, weight).c_str(), to_string(mode->getFps()).c_str(), - layerScore); - fixedRateBelowThresholdLayersScore.modeAboveThreshold += weightedLayerScore; - } else { - ALOGV("%s gives %s fixed source (below threshold) score of %.4f", - formatLayerInfo(layer, weight).c_str(), to_string(mode->getFps()).c_str(), - layerScore); - fixedRateBelowThresholdLayersScore.modeBelowThreshold += weightedLayerScore; - } - } else { - ALOGV("%s gives %s score of %.4f", formatLayerInfo(layer, weight).c_str(), - to_string(mode->getFps()).c_str(), layerScore); - overallScore += weightedLayerScore; - } - } - } - - // We want to find the best refresh rate without the fixed source layers, - // so we could know whether we should add the modeAboveThreshold scores or not. - // If the best refresh rate is already above the threshold, it means that - // some non-fixed source layers already scored it, so we can just add the score - // for all fixed source layers, even the ones that are above the threshold. - const bool maxScoreAboveThreshold = [&] { - if (mConfig.frameRateMultipleThreshold == 0 || scores.empty()) { - return false; - } - - const auto maxScoreIt = - std::max_element(scores.begin(), scores.end(), - [](RefreshRateScore max, RefreshRateScore current) { - const auto& [modeIt, overallScore, _] = current; - return overallScore > max.overallScore; - }); - ALOGV("%s is the best refresh rate without fixed source layers. It is %s the threshold for " - "refresh rate multiples", - to_string(maxScoreIt->modeIt->second->getFps()).c_str(), - maxScoreAboveThreshold ? "above" : "below"); - return maxScoreIt->modeIt->second->getFps() >= - Fps::fromValue(mConfig.frameRateMultipleThreshold); - }(); - - // Now we can add the fixed rate layers score - for (auto& [modeIt, overallScore, fixedRateBelowThresholdLayersScore] : scores) { - overallScore += fixedRateBelowThresholdLayersScore.modeBelowThreshold; - if (maxScoreAboveThreshold) { - overallScore += fixedRateBelowThresholdLayersScore.modeAboveThreshold; - } - ALOGV("%s adjusted overallScore is %.4f", to_string(modeIt->second->getFps()).c_str(), - overallScore); - } - - // Now that we scored all the refresh rates we need to pick the one that got the highest - // overallScore. Sort the scores based on their overallScore in descending order of priority. - const RefreshRateOrder refreshRateOrder = - maxVoteLayers > 0 ? RefreshRateOrder::Descending : RefreshRateOrder::Ascending; - std::sort(scores.begin(), scores.end(), - RefreshRateScoreComparator{.refreshRateOrder = refreshRateOrder}); - - RefreshRateRanking ranking; - ranking.reserve(scores.size()); - - std::transform(scores.begin(), scores.end(), back_inserter(ranking), - [](const RefreshRateScore& score) { - return ScoredRefreshRate{score.modeIt->second, score.overallScore}; - }); - - const bool noLayerScore = std::all_of(scores.begin(), scores.end(), [](RefreshRateScore score) { - return score.overallScore == 0; - }); - - if (primaryRangeIsSingleRate) { - // If we never scored any layers, then choose the rate from the primary - // range instead of picking a random score from the app range. - if (noLayerScore) { - ALOGV("Layers not scored"); - return {rankRefreshRates(anchorGroup, RefreshRateOrder::Descending), kNoSignals}; - } else { - return {ranking, kNoSignals}; - } - } - - // Consider the touch event if there are no ExplicitDefault layers. ExplicitDefault are mostly - // interactive (as opposed to ExplicitExactOrMultiple) and therefore if those posted an explicit - // vote we should not change it if we get a touch event. Only apply touch boost if it will - // actually increase the refresh rate over the normal selection. - const bool touchBoostForExplicitExact = [&] { - if (mSupportsFrameRateOverrideByContent) { - // Enable touch boost if there are other layers besides exact - return explicitExact + noVoteLayers != layers.size(); - } else { - // Enable touch boost if there are no exact layers - return explicitExact == 0; - } - }(); - - const auto touchRefreshRates = rankRefreshRates(anchorGroup, RefreshRateOrder::Descending); - - using fps_approx_ops::operator<; - - if (signals.touch && explicitDefaultVoteLayers == 0 && touchBoostForExplicitExact && - scores.front().modeIt->second->getFps() < touchRefreshRates.front().modePtr->getFps()) { - ALOGV("Touch Boost"); - return {touchRefreshRates, GlobalSignals{.touch = true}}; - } - - // If we never scored any layers, and we don't favor high refresh rates, prefer to stay with the - // current config - if (noLayerScore && refreshRateOrder == RefreshRateOrder::Ascending) { - const auto preferredDisplayMode = activeMode.getId(); - return {rankRefreshRates(anchorGroup, RefreshRateOrder::Ascending, preferredDisplayMode), - kNoSignals}; - } - - return {ranking, kNoSignals}; -} - -std::unordered_map> -groupLayersByUid(const std::vector& layers) { - std::unordered_map> layersByUid; - for (const auto& layer : layers) { - auto iter = layersByUid.emplace(layer.ownerUid, - std::vector()); - auto& layersWithSameUid = iter.first->second; - layersWithSameUid.push_back(&layer); - } - - // Remove uids that can't have a frame rate override - for (auto iter = layersByUid.begin(); iter != layersByUid.end();) { - const auto& layersWithSameUid = iter->second; - bool skipUid = false; - for (const auto& layer : layersWithSameUid) { - if (layer->vote == RefreshRateConfigs::LayerVoteType::Max || - layer->vote == RefreshRateConfigs::LayerVoteType::Heuristic) { - skipUid = true; - break; - } - } - if (skipUid) { - iter = layersByUid.erase(iter); - } else { - ++iter; - } - } - - return layersByUid; -} - -RefreshRateConfigs::UidToFrameRateOverride RefreshRateConfigs::getFrameRateOverrides( - const std::vector& layers, Fps displayRefreshRate, - GlobalSignals globalSignals) const { - ATRACE_CALL(); - - ALOGV("%s: %zu layers", __func__, layers.size()); - - std::lock_guard lock(mLock); - - std::vector scores; - scores.reserve(mDisplayModes.size()); - - for (auto it = mDisplayModes.begin(); it != mDisplayModes.end(); ++it) { - scores.emplace_back(RefreshRateScore{it, 0.0f}); - } - - std::sort(scores.begin(), scores.end(), [](const auto& lhs, const auto& rhs) { - const auto& mode1 = lhs.modeIt->second; - const auto& mode2 = rhs.modeIt->second; - return isStrictlyLess(mode1->getFps(), mode2->getFps()); - }); - - std::unordered_map> layersByUid = - groupLayersByUid(layers); - UidToFrameRateOverride frameRateOverrides; - for (const auto& [uid, layersWithSameUid] : layersByUid) { - // Layers with ExplicitExactOrMultiple expect touch boost - const bool hasExplicitExactOrMultiple = - std::any_of(layersWithSameUid.cbegin(), layersWithSameUid.cend(), - [](const auto& layer) { - return layer->vote == LayerVoteType::ExplicitExactOrMultiple; - }); - - if (globalSignals.touch && hasExplicitExactOrMultiple) { - continue; - } - - for (auto& [_, score, _1] : scores) { - score = 0; - } - - for (const auto& layer : layersWithSameUid) { - if (layer->vote == LayerVoteType::NoVote || layer->vote == LayerVoteType::Min) { - continue; - } - - LOG_ALWAYS_FATAL_IF(layer->vote != LayerVoteType::ExplicitDefault && - layer->vote != LayerVoteType::ExplicitExactOrMultiple && - layer->vote != LayerVoteType::ExplicitExact); - for (auto& [modeIt, score, _] : scores) { - constexpr bool isSeamlessSwitch = true; - const auto layerScore = calculateLayerScoreLocked(*layer, modeIt->second->getFps(), - isSeamlessSwitch); - score += layer->weight * layerScore; - } - } - - // We just care about the refresh rates which are a divisor of the - // display refresh rate - const auto it = std::remove_if(scores.begin(), scores.end(), [&](RefreshRateScore score) { - const auto& [id, mode] = *score.modeIt; - return getFrameRateDivisor(displayRefreshRate, mode->getFps()) == 0; - }); - scores.erase(it, scores.end()); - - // If we never scored any layers, we don't have a preferred frame rate - if (std::all_of(scores.begin(), scores.end(), - [](RefreshRateScore score) { return score.overallScore == 0; })) { - continue; - } - - // Now that we scored all the refresh rates we need to pick the lowest refresh rate - // that got the highest score. - const DisplayModePtr& bestRefreshRate = - std::min_element(scores.begin(), scores.end(), - RefreshRateScoreComparator{.refreshRateOrder = - RefreshRateOrder::Ascending}) - ->modeIt->second; - frameRateOverrides.emplace(uid, bestRefreshRate->getFps()); - } - - return frameRateOverrides; -} - -std::optional RefreshRateConfigs::onKernelTimerChanged( - std::optional desiredActiveModeId, bool timerExpired) const { - std::lock_guard lock(mLock); - - const DisplayModePtr& current = desiredActiveModeId - ? mDisplayModes.get(*desiredActiveModeId)->get() - : getActiveModeItLocked()->second; - - const DisplayModePtr& min = mMinRefreshRateModeIt->second; - if (current == min) { - return {}; - } - - const auto& mode = timerExpired ? min : current; - return mode->getFps(); -} - -const DisplayModePtr& RefreshRateConfigs::getMinRefreshRateByPolicyLocked() const { - const auto& activeMode = *getActiveModeItLocked()->second; - - for (const DisplayModeIterator modeIt : mPrimaryRefreshRates) { - const auto& mode = modeIt->second; - if (activeMode.getGroup() == mode->getGroup()) { - return mode; - } - } - - ALOGE("Can't find min refresh rate by policy with the same mode group as the current mode %s", - to_string(activeMode).c_str()); - - // Default to the lowest refresh rate. - return mPrimaryRefreshRates.front()->second; -} - -const DisplayModePtr& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked(int anchorGroup) const { - for (auto it = mPrimaryRefreshRates.rbegin(); it != mPrimaryRefreshRates.rend(); ++it) { - const auto& mode = (*it)->second; - if (anchorGroup == mode->getGroup()) { - return mode; - } - } - - ALOGE("Can't find max refresh rate by policy with the same group %d", anchorGroup); - - // Default to the highest refresh rate. - return mPrimaryRefreshRates.back()->second; -} - -auto RefreshRateConfigs::rankRefreshRates( - std::optional anchorGroupOpt, RefreshRateOrder refreshRateOrder, - std::optional preferredDisplayModeOpt) const -> RefreshRateRanking { - std::deque ranking; - - const auto rankRefreshRate = [&](DisplayModeIterator it) REQUIRES(mLock) { - const auto& mode = it->second; - if (anchorGroupOpt && mode->getGroup() != anchorGroupOpt) { - return; - } - - float score = calculateRefreshRateScoreForFps(mode->getFps()); - const bool inverseScore = (refreshRateOrder == RefreshRateOrder::Ascending); - if (inverseScore) { - score = 1.0f / score; - } - if (preferredDisplayModeOpt) { - if (*preferredDisplayModeOpt == mode->getId()) { - constexpr float kScore = std::numeric_limits::max(); - ranking.push_front(ScoredRefreshRate{mode, kScore}); - return; - } - constexpr float kNonPreferredModePenalty = 0.95f; - score *= kNonPreferredModePenalty; - } - ranking.push_back(ScoredRefreshRate{mode, score}); - }; - - if (refreshRateOrder == RefreshRateOrder::Ascending) { - std::for_each(mPrimaryRefreshRates.begin(), mPrimaryRefreshRates.end(), rankRefreshRate); - } else { - std::for_each(mPrimaryRefreshRates.rbegin(), mPrimaryRefreshRates.rend(), rankRefreshRate); - } - - if (!ranking.empty() || !anchorGroupOpt) { - return {ranking.begin(), ranking.end()}; - } - - ALOGW("Can't find %s refresh rate by policy with the same mode group" - " as the mode group %d", - refreshRateOrder == RefreshRateOrder::Ascending ? "min" : "max", anchorGroupOpt.value()); - - constexpr std::optional kNoAnchorGroup = std::nullopt; - return rankRefreshRates(kNoAnchorGroup, refreshRateOrder, preferredDisplayModeOpt); -} - -DisplayModePtr RefreshRateConfigs::getActiveModePtr() const { - std::lock_guard lock(mLock); - return getActiveModeItLocked()->second; -} - -const DisplayMode& RefreshRateConfigs::getActiveMode() const { - // Reads from kMainThreadContext do not require mLock. - ftl::FakeGuard guard(mLock); - return *mActiveModeIt->second; -} - -DisplayModeIterator RefreshRateConfigs::getActiveModeItLocked() const { - // Reads under mLock do not require kMainThreadContext. - return FTL_FAKE_GUARD(kMainThreadContext, mActiveModeIt); -} - -void RefreshRateConfigs::setActiveModeId(DisplayModeId modeId) { - std::lock_guard lock(mLock); - - // Invalidate the cached invocation to getRankedRefreshRates. This forces - // the refresh rate to be recomputed on the next call to getRankedRefreshRates. - mGetRankedRefreshRatesCache.reset(); - - mActiveModeIt = mDisplayModes.find(modeId); - LOG_ALWAYS_FATAL_IF(mActiveModeIt == mDisplayModes.end()); -} - -RefreshRateConfigs::RefreshRateConfigs(DisplayModes modes, DisplayModeId activeModeId, - Config config) - : mKnownFrameRates(constructKnownFrameRates(modes)), mConfig(config) { - initializeIdleTimer(); - FTL_FAKE_GUARD(kMainThreadContext, updateDisplayModes(std::move(modes), activeModeId)); -} - -void RefreshRateConfigs::initializeIdleTimer() { - if (mConfig.idleTimerTimeout > 0ms) { - mIdleTimer.emplace( - "IdleTimer", mConfig.idleTimerTimeout, - [this] { - std::scoped_lock lock(mIdleTimerCallbacksMutex); - if (const auto callbacks = getIdleTimerCallbacks()) { - callbacks->onReset(); - } - }, - [this] { - std::scoped_lock lock(mIdleTimerCallbacksMutex); - if (const auto callbacks = getIdleTimerCallbacks()) { - callbacks->onExpired(); - } - }); - } -} - -void RefreshRateConfigs::updateDisplayModes(DisplayModes modes, DisplayModeId activeModeId) { - std::lock_guard lock(mLock); - - // Invalidate the cached invocation to getRankedRefreshRates. This forces - // the refresh rate to be recomputed on the next call to getRankedRefreshRates. - mGetRankedRefreshRatesCache.reset(); - - mDisplayModes = std::move(modes); - mActiveModeIt = mDisplayModes.find(activeModeId); - LOG_ALWAYS_FATAL_IF(mActiveModeIt == mDisplayModes.end()); - - const auto sortedModes = - sortByRefreshRate(mDisplayModes, [](const DisplayMode&) { return true; }); - mMinRefreshRateModeIt = sortedModes.front(); - mMaxRefreshRateModeIt = sortedModes.back(); - - // Reset the policy because the old one may no longer be valid. - mDisplayManagerPolicy = {}; - mDisplayManagerPolicy.defaultMode = activeModeId; - - mSupportsFrameRateOverrideByContent = - mConfig.enableFrameRateOverride && canModesSupportFrameRateOverride(sortedModes); - - constructAvailableRefreshRates(); -} - -bool RefreshRateConfigs::isPolicyValidLocked(const Policy& policy) const { - // defaultMode must be a valid mode, and within the given refresh rate range. - if (const auto mode = mDisplayModes.get(policy.defaultMode)) { - if (!policy.primaryRange.includes(mode->get()->getFps())) { - ALOGE("Default mode is not in the primary range."); - return false; - } - } else { - ALOGE("Default mode is not found."); - return false; - } - - using namespace fps_approx_ops; - return policy.appRequestRange.min <= policy.primaryRange.min && - policy.appRequestRange.max >= policy.primaryRange.max; -} - -auto RefreshRateConfigs::setPolicy(const PolicyVariant& policy) -> SetPolicyResult { - Policy oldPolicy; - { - std::lock_guard lock(mLock); - oldPolicy = *getCurrentPolicyLocked(); - - const bool valid = ftl::match( - policy, - [this](const auto& policy) { - ftl::FakeGuard guard(mLock); - if (!isPolicyValidLocked(policy)) { - ALOGE("Invalid policy: %s", policy.toString().c_str()); - return false; - } - - using T = std::decay_t; - - if constexpr (std::is_same_v) { - mDisplayManagerPolicy = policy; - } else { - static_assert(std::is_same_v); - mOverridePolicy = policy; - } - return true; - }, - [this](NoOverridePolicy) { - ftl::FakeGuard guard(mLock); - mOverridePolicy.reset(); - return true; - }); - - if (!valid) { - return SetPolicyResult::Invalid; - } - - mGetRankedRefreshRatesCache.reset(); - - if (*getCurrentPolicyLocked() == oldPolicy) { - return SetPolicyResult::Unchanged; - } - constructAvailableRefreshRates(); - } - - const auto displayId = getActiveMode().getPhysicalDisplayId(); - const unsigned numModeChanges = std::exchange(mNumModeSwitchesInPolicy, 0u); - - ALOGI("Display %s policy changed\n" - "Previous: %s\n" - "Current: %s\n" - "%u mode changes were performed under the previous policy", - to_string(displayId).c_str(), oldPolicy.toString().c_str(), toString(policy).c_str(), - numModeChanges); - - return SetPolicyResult::Changed; -} - -const RefreshRateConfigs::Policy* RefreshRateConfigs::getCurrentPolicyLocked() const { - return mOverridePolicy ? &mOverridePolicy.value() : &mDisplayManagerPolicy; -} - -RefreshRateConfigs::Policy RefreshRateConfigs::getCurrentPolicy() const { - std::lock_guard lock(mLock); - return *getCurrentPolicyLocked(); -} - -RefreshRateConfigs::Policy RefreshRateConfigs::getDisplayManagerPolicy() const { - std::lock_guard lock(mLock); - return mDisplayManagerPolicy; -} - -bool RefreshRateConfigs::isModeAllowed(DisplayModeId modeId) const { - std::lock_guard lock(mLock); - return std::any_of(mAppRequestRefreshRates.begin(), mAppRequestRefreshRates.end(), - [modeId](DisplayModeIterator modeIt) { - return modeIt->second->getId() == modeId; - }); -} - -void RefreshRateConfigs::constructAvailableRefreshRates() { - // Filter modes based on current policy and sort on refresh rate. - const Policy* policy = getCurrentPolicyLocked(); - ALOGV("%s: %s ", __func__, policy->toString().c_str()); - - const auto& defaultMode = mDisplayModes.get(policy->defaultMode)->get(); - - const auto filterRefreshRates = [&](FpsRange range, const char* rangeName) REQUIRES(mLock) { - const auto filter = [&](const DisplayMode& mode) { - return mode.getResolution() == defaultMode->getResolution() && - mode.getDpi() == defaultMode->getDpi() && - (policy->allowGroupSwitching || mode.getGroup() == defaultMode->getGroup()) && - range.includes(mode.getFps()); - }; - - const auto modes = sortByRefreshRate(mDisplayModes, filter); - LOG_ALWAYS_FATAL_IF(modes.empty(), "No matching modes for %s range %s", rangeName, - to_string(range).c_str()); - - const auto stringifyModes = [&] { - std::string str; - for (const auto modeIt : modes) { - str += to_string(modeIt->second->getFps()); - str.push_back(' '); - } - return str; - }; - ALOGV("%s refresh rates: %s", rangeName, stringifyModes().c_str()); - - return modes; - }; - - mPrimaryRefreshRates = filterRefreshRates(policy->primaryRange, "primary"); - mAppRequestRefreshRates = filterRefreshRates(policy->appRequestRange, "app request"); -} - -Fps RefreshRateConfigs::findClosestKnownFrameRate(Fps frameRate) const { - using namespace fps_approx_ops; - - if (frameRate <= mKnownFrameRates.front()) { - return mKnownFrameRates.front(); - } - - if (frameRate >= mKnownFrameRates.back()) { - return mKnownFrameRates.back(); - } - - auto lowerBound = std::lower_bound(mKnownFrameRates.begin(), mKnownFrameRates.end(), frameRate, - isStrictlyLess); - - const auto distance1 = std::abs(frameRate.getValue() - lowerBound->getValue()); - const auto distance2 = std::abs(frameRate.getValue() - std::prev(lowerBound)->getValue()); - return distance1 < distance2 ? *lowerBound : *std::prev(lowerBound); -} - -RefreshRateConfigs::KernelIdleTimerAction RefreshRateConfigs::getIdleTimerAction() const { - std::lock_guard lock(mLock); - - const Fps deviceMinFps = mMinRefreshRateModeIt->second->getFps(); - const DisplayModePtr& minByPolicy = getMinRefreshRateByPolicyLocked(); - - // Kernel idle timer will set the refresh rate to the device min. If DisplayManager says that - // the min allowed refresh rate is higher than the device min, we do not want to enable the - // timer. - if (isStrictlyLess(deviceMinFps, minByPolicy->getFps())) { - return KernelIdleTimerAction::TurnOff; - } - - const DisplayModePtr& maxByPolicy = - getMaxRefreshRateByPolicyLocked(getActiveModeItLocked()->second->getGroup()); - if (minByPolicy == maxByPolicy) { - // Turn on the timer when the min of the primary range is below the device min. - if (const Policy* currentPolicy = getCurrentPolicyLocked(); - isApproxLess(currentPolicy->primaryRange.min, deviceMinFps)) { - return KernelIdleTimerAction::TurnOn; - } - return KernelIdleTimerAction::TurnOff; - } - - // Turn on the timer in all other cases. - return KernelIdleTimerAction::TurnOn; -} - -int RefreshRateConfigs::getFrameRateDivisor(Fps displayRefreshRate, Fps layerFrameRate) { - // This calculation needs to be in sync with the java code - // in DisplayManagerService.getDisplayInfoForFrameRateOverride - - // The threshold must be smaller than 0.001 in order to differentiate - // between the fractional pairs (e.g. 59.94 and 60). - constexpr float kThreshold = 0.0009f; - const auto numPeriods = displayRefreshRate.getValue() / layerFrameRate.getValue(); - const auto numPeriodsRounded = std::round(numPeriods); - if (std::abs(numPeriods - numPeriodsRounded) > kThreshold) { - return 0; - } - - return static_cast(numPeriodsRounded); -} - -bool RefreshRateConfigs::isFractionalPairOrMultiple(Fps smaller, Fps bigger) { - if (isStrictlyLess(bigger, smaller)) { - return isFractionalPairOrMultiple(bigger, smaller); - } - - const auto multiplier = std::round(bigger.getValue() / smaller.getValue()); - constexpr float kCoef = 1000.f / 1001.f; - return isApproxEqual(bigger, Fps::fromValue(smaller.getValue() * multiplier / kCoef)) || - isApproxEqual(bigger, Fps::fromValue(smaller.getValue() * multiplier * kCoef)); -} - -void RefreshRateConfigs::dump(utils::Dumper& dumper) const { - using namespace std::string_view_literals; - - std::lock_guard lock(mLock); - - const auto activeModeId = getActiveModeItLocked()->first; - dumper.dump("activeModeId"sv, std::to_string(activeModeId.value())); - - dumper.dump("displayModes"sv); - { - utils::Dumper::Indent indent(dumper); - for (const auto& [id, mode] : mDisplayModes) { - dumper.dump({}, to_string(*mode)); - } - } - - dumper.dump("displayManagerPolicy"sv, mDisplayManagerPolicy.toString()); - - if (const Policy& currentPolicy = *getCurrentPolicyLocked(); - mOverridePolicy && currentPolicy != mDisplayManagerPolicy) { - dumper.dump("overridePolicy"sv, currentPolicy.toString()); - } - - dumper.dump("supportsFrameRateOverrideByContent"sv, mSupportsFrameRateOverrideByContent); - - std::string idleTimer; - if (mIdleTimer) { - idleTimer = mIdleTimer->dump(); - } else { - idleTimer = "off"sv; - } - - if (const auto controller = mConfig.kernelIdleTimerController) { - base::StringAppendF(&idleTimer, " (kernel via %s)", ftl::enum_string(*controller).c_str()); - } else { - idleTimer += " (platform)"sv; - } - - dumper.dump("idleTimer"sv, idleTimer); -} - -std::chrono::milliseconds RefreshRateConfigs::getIdleTimerTimeout() { - return mConfig.idleTimerTimeout; -} - -} // namespace android::scheduler - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wextra" diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h deleted file mode 100644 index 99f81aa75e..0000000000 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ /dev/null @@ -1,475 +0,0 @@ -/* - * Copyright 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include "DisplayHardware/DisplayMode.h" -#include "DisplayHardware/HWComposer.h" -#include "Scheduler/OneShotTimer.h" -#include "Scheduler/StrongTyping.h" -#include "ThreadContext.h" -#include "Utils/Dumper.h" - -namespace android::scheduler { - -using namespace std::chrono_literals; - -enum class DisplayModeEvent : unsigned { None = 0b0, Changed = 0b1 }; - -inline DisplayModeEvent operator|(DisplayModeEvent lhs, DisplayModeEvent rhs) { - using T = std::underlying_type_t; - return static_cast(static_cast(lhs) | static_cast(rhs)); -} - -using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride; - -/** - * This class is used to encapsulate configuration for refresh rates. It holds information - * about available refresh rates on the device, and the mapping between the numbers and human - * readable names. - */ -class RefreshRateConfigs { -public: - // Margin used when matching refresh rates to the content desired ones. - static constexpr nsecs_t MARGIN_FOR_PERIOD_CALCULATION = - std::chrono::nanoseconds(800us).count(); - - class Policy { - static constexpr int kAllowGroupSwitchingDefault = false; - - public: - // The default mode, used to ensure we only initiate display mode switches within the - // same mode group as defaultMode's group. - DisplayModeId defaultMode; - // Whether or not we switch mode groups to get the best frame rate. - bool allowGroupSwitching = kAllowGroupSwitchingDefault; - // The primary refresh rate range represents display manager's general guidance on the - // display modes we'll consider when switching refresh rates. Unless we get an explicit - // signal from an app, we should stay within this range. - FpsRange primaryRange; - // The app request refresh rate range allows us to consider more display modes when - // switching refresh rates. Although we should generally stay within the primary range, - // specific considerations, such as layer frame rate settings specified via the - // setFrameRate() api, may cause us to go outside the primary range. We never go outside the - // app request range. The app request range will be greater than or equal to the primary - // refresh rate range, never smaller. - FpsRange appRequestRange; - - Policy() = default; - - Policy(DisplayModeId defaultMode, FpsRange range) - : Policy(defaultMode, kAllowGroupSwitchingDefault, range, range) {} - - Policy(DisplayModeId defaultMode, bool allowGroupSwitching, FpsRange range) - : Policy(defaultMode, allowGroupSwitching, range, range) {} - - Policy(DisplayModeId defaultMode, FpsRange primaryRange, FpsRange appRequestRange) - : Policy(defaultMode, kAllowGroupSwitchingDefault, primaryRange, appRequestRange) {} - - Policy(DisplayModeId defaultMode, bool allowGroupSwitching, FpsRange primaryRange, - FpsRange appRequestRange) - : defaultMode(defaultMode), - allowGroupSwitching(allowGroupSwitching), - primaryRange(primaryRange), - appRequestRange(appRequestRange) {} - - bool operator==(const Policy& other) const { - using namespace fps_approx_ops; - return defaultMode == other.defaultMode && primaryRange == other.primaryRange && - appRequestRange == other.appRequestRange && - allowGroupSwitching == other.allowGroupSwitching; - } - - bool operator!=(const Policy& other) const { return !(*this == other); } - std::string toString() const; - }; - - enum class SetPolicyResult { Invalid, Unchanged, Changed }; - - // We maintain the display manager policy and the override policy separately. The override - // policy is used by CTS tests to get a consistent device state for testing. While the override - // policy is set, it takes precedence over the display manager policy. Once the override policy - // is cleared, we revert to using the display manager policy. - struct DisplayManagerPolicy : Policy { - using Policy::Policy; - }; - - struct OverridePolicy : Policy { - using Policy::Policy; - }; - - struct NoOverridePolicy {}; - - using PolicyVariant = std::variant; - - SetPolicyResult setPolicy(const PolicyVariant&) EXCLUDES(mLock) REQUIRES(kMainThreadContext); - - void onModeChangeInitiated() REQUIRES(kMainThreadContext) { mNumModeSwitchesInPolicy++; } - - // Gets the current policy, which will be the override policy if active, and the display manager - // policy otherwise. - Policy getCurrentPolicy() const EXCLUDES(mLock); - // Gets the display manager policy, regardless of whether an override policy is active. - Policy getDisplayManagerPolicy() const EXCLUDES(mLock); - - // Returns true if mode is allowed by the current policy. - bool isModeAllowed(DisplayModeId) const EXCLUDES(mLock); - - // Describes the different options the layer voted for refresh rate - enum class LayerVoteType { - NoVote, // Doesn't care about the refresh rate - Min, // Minimal refresh rate available - Max, // Maximal refresh rate available - Heuristic, // Specific refresh rate that was calculated by platform using a heuristic - ExplicitDefault, // Specific refresh rate that was provided by the app with Default - // compatibility - ExplicitExactOrMultiple, // Specific refresh rate that was provided by the app with - // ExactOrMultiple compatibility - ExplicitExact, // Specific refresh rate that was provided by the app with - // Exact compatibility - - ftl_last = ExplicitExact - }; - - // Captures the layer requirements for a refresh rate. This will be used to determine the - // display refresh rate. - struct LayerRequirement { - // Layer's name. Used for debugging purposes. - std::string name; - // Layer's owner uid - uid_t ownerUid = static_cast(-1); - // Layer vote type. - LayerVoteType vote = LayerVoteType::NoVote; - // Layer's desired refresh rate, if applicable. - Fps desiredRefreshRate; - // If a seamless mode switch is required. - Seamlessness seamlessness = Seamlessness::Default; - // Layer's weight in the range of [0, 1]. The higher the weight the more impact this layer - // would have on choosing the refresh rate. - float weight = 0.0f; - // Whether layer is in focus or not based on WindowManager's state - bool focused = false; - - bool operator==(const LayerRequirement& other) const { - return name == other.name && vote == other.vote && - isApproxEqual(desiredRefreshRate, other.desiredRefreshRate) && - seamlessness == other.seamlessness && weight == other.weight && - focused == other.focused; - } - - bool operator!=(const LayerRequirement& other) const { return !(*this == other); } - }; - - // Global state describing signals that affect refresh rate choice. - struct GlobalSignals { - // Whether the user touched the screen recently. Used to apply touch boost. - bool touch = false; - // True if the system hasn't seen any buffers posted to layers recently. - bool idle = false; - // Whether the display is about to be powered on, or has been in PowerMode::ON - // within the timeout of DisplayPowerTimer. - bool powerOnImminent = false; - - bool operator==(GlobalSignals other) const { - return touch == other.touch && idle == other.idle && - powerOnImminent == other.powerOnImminent; - } - - auto toString() const { - return ftl::Concat("{touch=", touch, ", idle=", idle, - ", powerOnImminent=", powerOnImminent, '}'); - } - }; - - struct ScoredRefreshRate { - DisplayModePtr modePtr; - float score = 0.0f; - - bool operator==(const ScoredRefreshRate& other) const { - return modePtr == other.modePtr && score == other.score; - } - - static bool scoresEqual(float lhs, float rhs) { - constexpr float kEpsilon = 0.0001f; - return std::abs(lhs - rhs) <= kEpsilon; - } - - struct DescendingScore { - bool operator()(const ScoredRefreshRate& lhs, const ScoredRefreshRate& rhs) const { - return lhs.score > rhs.score && !scoresEqual(lhs.score, rhs.score); - } - }; - }; - - using RefreshRateRanking = std::vector; - - struct RankedRefreshRates { - RefreshRateRanking ranking; // Ordered by descending score. - GlobalSignals consideredSignals; - - bool operator==(const RankedRefreshRates& other) const { - return ranking == other.ranking && consideredSignals == other.consideredSignals; - } - }; - - RankedRefreshRates getRankedRefreshRates(const std::vector&, - GlobalSignals) const EXCLUDES(mLock); - - FpsRange getSupportedRefreshRateRange() const EXCLUDES(mLock) { - std::lock_guard lock(mLock); - return {mMinRefreshRateModeIt->second->getFps(), mMaxRefreshRateModeIt->second->getFps()}; - } - - std::optional onKernelTimerChanged(std::optional desiredActiveModeId, - bool timerExpired) const EXCLUDES(mLock); - - void setActiveModeId(DisplayModeId) EXCLUDES(mLock) REQUIRES(kMainThreadContext); - - // See mActiveModeIt for thread safety. - DisplayModePtr getActiveModePtr() const EXCLUDES(mLock); - const DisplayMode& getActiveMode() const REQUIRES(kMainThreadContext); - - // Returns a known frame rate that is the closest to frameRate - Fps findClosestKnownFrameRate(Fps frameRate) const; - - enum class KernelIdleTimerController { Sysprop, HwcApi, ftl_last = HwcApi }; - - // Configuration flags. - struct Config { - bool enableFrameRateOverride = false; - - // Specifies the upper refresh rate threshold (inclusive) for layer vote types of multiple - // or heuristic, such that refresh rates higher than this value will not be voted for. 0 if - // no threshold is set. - int frameRateMultipleThreshold = 0; - - // The Idle Timer timeout. 0 timeout means no idle timer. - std::chrono::milliseconds idleTimerTimeout = 0ms; - - // The controller representing how the kernel idle timer will be configured - // either on the HWC api or sysprop. - std::optional kernelIdleTimerController; - }; - - RefreshRateConfigs(DisplayModes, DisplayModeId activeModeId, - Config config = {.enableFrameRateOverride = false, - .frameRateMultipleThreshold = 0, - .idleTimerTimeout = 0ms, - .kernelIdleTimerController = {}}); - - RefreshRateConfigs(const RefreshRateConfigs&) = delete; - RefreshRateConfigs& operator=(const RefreshRateConfigs&) = delete; - - // Returns whether switching modes (refresh rate or resolution) is possible. - // TODO(b/158780872): Consider HAL support, and skip frame rate detection if the modes only - // differ in resolution. - bool canSwitch() const EXCLUDES(mLock) { - std::lock_guard lock(mLock); - return mDisplayModes.size() > 1; - } - - // Class to enumerate options around toggling the kernel timer on and off. - enum class KernelIdleTimerAction { - TurnOff, // Turn off the idle timer. - TurnOn // Turn on the idle timer. - }; - - // Checks whether kernel idle timer should be active depending the policy decisions around - // refresh rates. - KernelIdleTimerAction getIdleTimerAction() const; - - bool supportsFrameRateOverrideByContent() const { return mSupportsFrameRateOverrideByContent; } - - // Return the display refresh rate divisor to match the layer - // frame rate, or 0 if the display refresh rate is not a multiple of the - // layer refresh rate. - static int getFrameRateDivisor(Fps displayRefreshRate, Fps layerFrameRate); - - // Returns if the provided frame rates have a ratio t*1000/1001 or t*1001/1000 - // for an integer t. - static bool isFractionalPairOrMultiple(Fps, Fps); - - using UidToFrameRateOverride = std::map; - - // Returns the frame rate override for each uid. - UidToFrameRateOverride getFrameRateOverrides(const std::vector&, - Fps displayFrameRate, GlobalSignals) const - EXCLUDES(mLock); - - std::optional kernelIdleTimerController() { - return mConfig.kernelIdleTimerController; - } - - struct IdleTimerCallbacks { - struct Callbacks { - std::function onReset; - std::function onExpired; - }; - - Callbacks platform; - Callbacks kernel; - }; - - void setIdleTimerCallbacks(IdleTimerCallbacks callbacks) EXCLUDES(mIdleTimerCallbacksMutex) { - std::scoped_lock lock(mIdleTimerCallbacksMutex); - mIdleTimerCallbacks = std::move(callbacks); - } - - void clearIdleTimerCallbacks() EXCLUDES(mIdleTimerCallbacksMutex) { - std::scoped_lock lock(mIdleTimerCallbacksMutex); - mIdleTimerCallbacks.reset(); - } - - void startIdleTimer() { - if (mIdleTimer) { - mIdleTimer->start(); - } - } - - void stopIdleTimer() { - if (mIdleTimer) { - mIdleTimer->stop(); - } - } - - void resetIdleTimer(bool kernelOnly) { - if (!mIdleTimer) { - return; - } - if (kernelOnly && !mConfig.kernelIdleTimerController.has_value()) { - return; - } - mIdleTimer->reset(); - } - - void dump(utils::Dumper&) const EXCLUDES(mLock); - - std::chrono::milliseconds getIdleTimerTimeout(); - -private: - friend struct TestableRefreshRateConfigs; - - void constructAvailableRefreshRates() REQUIRES(mLock); - - // See mActiveModeIt for thread safety. - DisplayModeIterator getActiveModeItLocked() const REQUIRES(mLock); - - RankedRefreshRates getRankedRefreshRatesLocked(const std::vector&, - GlobalSignals) const REQUIRES(mLock); - - // Returns number of display frames and remainder when dividing the layer refresh period by - // display refresh period. - std::pair getDisplayFrames(nsecs_t layerPeriod, nsecs_t displayPeriod) const; - - // Returns the lowest refresh rate according to the current policy. May change at runtime. Only - // uses the primary range, not the app request range. - const DisplayModePtr& getMinRefreshRateByPolicyLocked() const REQUIRES(mLock); - - // Returns the highest refresh rate according to the current policy. May change at runtime. Only - // uses the primary range, not the app request range. - const DisplayModePtr& getMaxRefreshRateByPolicyLocked(int anchorGroup) const REQUIRES(mLock); - - struct RefreshRateScoreComparator; - - enum class RefreshRateOrder { Ascending, Descending }; - - // Only uses the primary range, not the app request range. - RefreshRateRanking rankRefreshRates(std::optional anchorGroupOpt, RefreshRateOrder, - std::optional preferredDisplayModeOpt = - std::nullopt) const REQUIRES(mLock); - - const Policy* getCurrentPolicyLocked() const REQUIRES(mLock); - bool isPolicyValidLocked(const Policy& policy) const REQUIRES(mLock); - - // Returns the refresh rate score as a ratio to max refresh rate, which has a score of 1. - float calculateRefreshRateScoreForFps(Fps refreshRate) const REQUIRES(mLock); - // calculates a score for a layer. Used to determine the display refresh rate - // and the frame rate override for certains applications. - float calculateLayerScoreLocked(const LayerRequirement&, Fps refreshRate, - bool isSeamlessSwitch) const REQUIRES(mLock); - - float calculateNonExactMatchingLayerScoreLocked(const LayerRequirement&, Fps refreshRate) const - REQUIRES(mLock); - - void updateDisplayModes(DisplayModes, DisplayModeId activeModeId) EXCLUDES(mLock) - REQUIRES(kMainThreadContext); - - void initializeIdleTimer(); - - std::optional getIdleTimerCallbacks() const - REQUIRES(mIdleTimerCallbacksMutex) { - if (!mIdleTimerCallbacks) return {}; - return mConfig.kernelIdleTimerController.has_value() ? mIdleTimerCallbacks->kernel - : mIdleTimerCallbacks->platform; - } - - // The display modes of the active display. The DisplayModeIterators below are pointers into - // this container, so must be invalidated whenever the DisplayModes change. The Policy below - // is also dependent, so must be reset as well. - DisplayModes mDisplayModes GUARDED_BY(mLock); - - // Written under mLock exclusively from kMainThreadContext, so reads from kMainThreadContext - // need not be under mLock. - DisplayModeIterator mActiveModeIt GUARDED_BY(mLock) GUARDED_BY(kMainThreadContext); - - DisplayModeIterator mMinRefreshRateModeIt GUARDED_BY(mLock); - DisplayModeIterator mMaxRefreshRateModeIt GUARDED_BY(mLock); - - // Display modes that satisfy the Policy's ranges, filtered and sorted by refresh rate. - std::vector mPrimaryRefreshRates GUARDED_BY(mLock); - std::vector mAppRequestRefreshRates GUARDED_BY(mLock); - - Policy mDisplayManagerPolicy GUARDED_BY(mLock); - std::optional mOverridePolicy GUARDED_BY(mLock); - - unsigned mNumModeSwitchesInPolicy GUARDED_BY(kMainThreadContext) = 0; - - mutable std::mutex mLock; - - // A sorted list of known frame rates that a Heuristic layer will choose - // from based on the closest value. - const std::vector mKnownFrameRates; - - const Config mConfig; - bool mSupportsFrameRateOverrideByContent; - - struct GetRankedRefreshRatesCache { - std::pair, GlobalSignals> arguments; - RankedRefreshRates result; - }; - mutable std::optional mGetRankedRefreshRatesCache GUARDED_BY(mLock); - - // Declare mIdleTimer last to ensure its thread joins before the mutex/callbacks are destroyed. - std::mutex mIdleTimerCallbacksMutex; - std::optional mIdleTimerCallbacks GUARDED_BY(mIdleTimerCallbacksMutex); - // Used to detect (lack of) frame activity. - std::optional mIdleTimer; -}; - -} // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp new file mode 100644 index 0000000000..40af6ee575 --- /dev/null +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp @@ -0,0 +1,1155 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// #define LOG_NDEBUG 0 +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wextra" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../SurfaceFlingerProperties.h" +#include "RefreshRateSelector.h" + +#undef LOG_TAG +#define LOG_TAG "RefreshRateSelector" + +namespace android::scheduler { +namespace { + +struct RefreshRateScore { + DisplayModeIterator modeIt; + float overallScore; + struct { + float modeBelowThreshold; + float modeAboveThreshold; + } fixedRateBelowThresholdLayersScore; +}; + +constexpr RefreshRateSelector::GlobalSignals kNoSignals; + +std::string formatLayerInfo(const RefreshRateSelector::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, + ftl::enum_string(layer.seamlessness).c_str(), + to_string(layer.desiredRefreshRate).c_str()); +} + +std::vector constructKnownFrameRates(const DisplayModes& modes) { + std::vector knownFrameRates = {24_Hz, 30_Hz, 45_Hz, 60_Hz, 72_Hz}; + knownFrameRates.reserve(knownFrameRates.size() + modes.size()); + + // Add all supported refresh rates. + for (const auto& [id, mode] : modes) { + knownFrameRates.push_back(mode->getFps()); + } + + // Sort and remove duplicates. + std::sort(knownFrameRates.begin(), knownFrameRates.end(), isStrictlyLess); + knownFrameRates.erase(std::unique(knownFrameRates.begin(), knownFrameRates.end(), + isApproxEqual), + knownFrameRates.end()); + return knownFrameRates; +} + +// The Filter is a `bool(const DisplayMode&)` predicate. +template +std::vector sortByRefreshRate(const DisplayModes& modes, Filter&& filter) { + std::vector sortedModes; + sortedModes.reserve(modes.size()); + + for (auto it = modes.begin(); it != modes.end(); ++it) { + const auto& [id, mode] = *it; + + if (filter(*mode)) { + ALOGV("%s: including mode %d", __func__, id.value()); + sortedModes.push_back(it); + } + } + + std::sort(sortedModes.begin(), sortedModes.end(), [](auto it1, auto it2) { + const auto& mode1 = it1->second; + const auto& mode2 = it2->second; + + if (mode1->getVsyncPeriod() == mode2->getVsyncPeriod()) { + return mode1->getGroup() > mode2->getGroup(); + } + + return mode1->getVsyncPeriod() > mode2->getVsyncPeriod(); + }); + + return sortedModes; +} + +bool canModesSupportFrameRateOverride(const std::vector& sortedModes) { + for (const auto it1 : sortedModes) { + const auto& mode1 = it1->second; + for (const auto it2 : sortedModes) { + const auto& mode2 = it2->second; + + if (RefreshRateSelector::getFrameRateDivisor(mode1->getFps(), mode2->getFps()) >= 2) { + return true; + } + } + } + return false; +} + +std::string toString(const RefreshRateSelector::PolicyVariant& policy) { + using namespace std::string_literals; + + return ftl::match( + policy, + [](const RefreshRateSelector::DisplayManagerPolicy& policy) { + return "DisplayManagerPolicy"s + policy.toString(); + }, + [](const RefreshRateSelector::OverridePolicy& policy) { + return "OverridePolicy"s + policy.toString(); + }, + [](RefreshRateSelector::NoOverridePolicy) { return "NoOverridePolicy"s; }); +} + +} // namespace + +struct RefreshRateSelector::RefreshRateScoreComparator { + bool operator()(const RefreshRateScore& lhs, const RefreshRateScore& rhs) const { + const auto& [modeIt, overallScore, _] = lhs; + + std::string name = to_string(modeIt->second->getFps()); + ALOGV("%s sorting scores %.2f", name.c_str(), overallScore); + + ATRACE_INT(name.c_str(), static_cast(std::round(overallScore * 100))); + + if (!ScoredRefreshRate::scoresEqual(overallScore, rhs.overallScore)) { + return overallScore > rhs.overallScore; + } + + // If overallScore tie we will pick the higher refresh rate if + // high refresh rate is the priority else the lower refresh rate. + if (refreshRateOrder == RefreshRateOrder::Descending) { + using fps_approx_ops::operator>; + return modeIt->second->getFps() > rhs.modeIt->second->getFps(); + } else { + using fps_approx_ops::operator<; + return modeIt->second->getFps() < rhs.modeIt->second->getFps(); + } + } + + const RefreshRateOrder refreshRateOrder; +}; + +std::string RefreshRateSelector::Policy::toString() const { + return base::StringPrintf("{defaultModeId=%d, allowGroupSwitching=%s" + ", primaryRange=%s, appRequestRange=%s}", + defaultMode.value(), allowGroupSwitching ? "true" : "false", + to_string(primaryRange).c_str(), to_string(appRequestRange).c_str()); +} + +std::pair RefreshRateSelector::getDisplayFrames(nsecs_t layerPeriod, + nsecs_t displayPeriod) const { + auto [quotient, remainder] = std::div(layerPeriod, displayPeriod); + if (remainder <= MARGIN_FOR_PERIOD_CALCULATION || + std::abs(remainder - displayPeriod) <= MARGIN_FOR_PERIOD_CALCULATION) { + quotient++; + remainder = 0; + } + + return {quotient, remainder}; +} + +float RefreshRateSelector::calculateNonExactMatchingLayerScoreLocked(const LayerRequirement& layer, + Fps refreshRate) const { + constexpr float kScoreForFractionalPairs = .8f; + + const auto displayPeriod = refreshRate.getPeriodNsecs(); + const auto layerPeriod = layer.desiredRefreshRate.getPeriodNsecs(); + if (layer.vote == LayerVoteType::ExplicitDefault) { + // Find the actual rate the layer will render, assuming + // that layerPeriod is the minimal period to render a frame. + // For example if layerPeriod is 20ms and displayPeriod is 16ms, + // then the actualLayerPeriod will be 32ms, because it is the + // smallest multiple of the display period which is >= layerPeriod. + auto actualLayerPeriod = displayPeriod; + int multiplier = 1; + while (layerPeriod > actualLayerPeriod + MARGIN_FOR_PERIOD_CALCULATION) { + multiplier++; + actualLayerPeriod = displayPeriod * multiplier; + } + + // Because of the threshold we used above it's possible that score is slightly + // above 1. + return std::min(1.0f, + static_cast(layerPeriod) / static_cast(actualLayerPeriod)); + } + + if (layer.vote == LayerVoteType::ExplicitExactOrMultiple || + layer.vote == LayerVoteType::Heuristic) { + if (isFractionalPairOrMultiple(refreshRate, layer.desiredRefreshRate)) { + return kScoreForFractionalPairs; + } + + // Calculate how many display vsyncs we need to present a single frame for this + // layer + const auto [displayFramesQuotient, displayFramesRemainder] = + getDisplayFrames(layerPeriod, displayPeriod); + static constexpr size_t MAX_FRAMES_TO_FIT = 10; // Stop calculating when score < 0.1 + if (displayFramesRemainder == 0) { + // Layer desired refresh rate matches the display rate. + return 1.0f; + } + + if (displayFramesQuotient == 0) { + // Layer desired refresh rate is higher than the display rate. + return (static_cast(layerPeriod) / static_cast(displayPeriod)) * + (1.0f / (MAX_FRAMES_TO_FIT + 1)); + } + + // Layer desired refresh rate is lower than the display rate. Check how well it fits + // the cadence. + auto diff = std::abs(displayFramesRemainder - (displayPeriod - displayFramesRemainder)); + int iter = 2; + while (diff > MARGIN_FOR_PERIOD_CALCULATION && iter < MAX_FRAMES_TO_FIT) { + diff = diff - (displayPeriod - diff); + iter++; + } + + return (1.0f / iter); + } + + return 0; +} + +float RefreshRateSelector::calculateRefreshRateScoreForFps(Fps refreshRate) const { + const float ratio = + refreshRate.getValue() / mAppRequestRefreshRates.back()->second->getFps().getValue(); + // Use ratio^2 to get a lower score the more we get further from peak + return ratio * ratio; +} + +float RefreshRateSelector::calculateLayerScoreLocked(const LayerRequirement& layer, Fps refreshRate, + bool isSeamlessSwitch) const { + // Slightly prefer seamless switches. + constexpr float kSeamedSwitchPenalty = 0.95f; + const float seamlessness = isSeamlessSwitch ? 1.0f : kSeamedSwitchPenalty; + + // If the layer wants Max, give higher score to the higher refresh rate + if (layer.vote == LayerVoteType::Max) { + return calculateRefreshRateScoreForFps(refreshRate); + } + + if (layer.vote == LayerVoteType::ExplicitExact) { + const int divisor = getFrameRateDivisor(refreshRate, layer.desiredRefreshRate); + if (mSupportsFrameRateOverrideByContent) { + // Since we support frame rate override, allow refresh rates which are + // multiples of the layer's request, as those apps would be throttled + // down to run at the desired refresh rate. + return divisor > 0; + } + + return divisor == 1; + } + + // If the layer frame rate is a divisor of the refresh rate it should score + // the highest score. + if (getFrameRateDivisor(refreshRate, layer.desiredRefreshRate) > 0) { + return 1.0f * seamlessness; + } + + // The layer frame rate is not a divisor of the refresh rate, + // there is a small penalty attached to the score to favor the frame rates + // the exactly matches the display refresh rate or a multiple. + constexpr float kNonExactMatchingPenalty = 0.95f; + return calculateNonExactMatchingLayerScoreLocked(layer, refreshRate) * seamlessness * + kNonExactMatchingPenalty; +} + +auto RefreshRateSelector::getRankedRefreshRates(const std::vector& layers, + GlobalSignals signals) const -> RankedRefreshRates { + std::lock_guard lock(mLock); + + if (mGetRankedRefreshRatesCache && + mGetRankedRefreshRatesCache->arguments == std::make_pair(layers, signals)) { + return mGetRankedRefreshRatesCache->result; + } + + const auto result = getRankedRefreshRatesLocked(layers, signals); + mGetRankedRefreshRatesCache = GetRankedRefreshRatesCache{{layers, signals}, result}; + return result; +} + +auto RefreshRateSelector::getRankedRefreshRatesLocked(const std::vector& layers, + GlobalSignals signals) const + -> RankedRefreshRates { + using namespace fps_approx_ops; + ATRACE_CALL(); + ALOGV("%s: %zu layers", __func__, layers.size()); + + const auto& activeMode = *getActiveModeItLocked()->second; + + // Keep the display at max refresh rate for the duration of powering on the display. + if (signals.powerOnImminent) { + ALOGV("Power On Imminent"); + return {rankRefreshRates(activeMode.getGroup(), RefreshRateOrder::Descending), + GlobalSignals{.powerOnImminent = true}}; + } + + int noVoteLayers = 0; + int minVoteLayers = 0; + int maxVoteLayers = 0; + int explicitDefaultVoteLayers = 0; + int explicitExactOrMultipleVoteLayers = 0; + int explicitExact = 0; + int seamedFocusedLayers = 0; + + for (const auto& layer : layers) { + switch (layer.vote) { + case LayerVoteType::NoVote: + noVoteLayers++; + break; + case LayerVoteType::Min: + minVoteLayers++; + break; + case LayerVoteType::Max: + maxVoteLayers++; + break; + case LayerVoteType::ExplicitDefault: + explicitDefaultVoteLayers++; + break; + case LayerVoteType::ExplicitExactOrMultiple: + explicitExactOrMultipleVoteLayers++; + break; + case LayerVoteType::ExplicitExact: + explicitExact++; + break; + case LayerVoteType::Heuristic: + break; + } + + if (layer.seamlessness == Seamlessness::SeamedAndSeamless && layer.focused) { + seamedFocusedLayers++; + } + } + + const bool hasExplicitVoteLayers = explicitDefaultVoteLayers > 0 || + explicitExactOrMultipleVoteLayers > 0 || explicitExact > 0; + + const Policy* policy = getCurrentPolicyLocked(); + const auto& defaultMode = mDisplayModes.get(policy->defaultMode)->get(); + + // If the default mode group is different from the group of current mode, + // this means a layer requesting a seamed mode switch just disappeared and + // we should switch back to the default group. + // However if a seamed layer is still present we anchor around the group + // of the current mode, in order to prevent unnecessary seamed mode switches + // (e.g. when pausing a video playback). + const auto anchorGroup = + seamedFocusedLayers > 0 ? activeMode.getGroup() : defaultMode->getGroup(); + + // 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 (signals.touch && !hasExplicitVoteLayers) { + ALOGV("Touch Boost"); + return {rankRefreshRates(anchorGroup, RefreshRateOrder::Descending), + GlobalSignals{.touch = true}}; + } + + // If the primary range consists of a single refresh rate then we can only + // move out the of range if layers explicitly request a different refresh + // rate. + const bool primaryRangeIsSingleRate = + isApproxEqual(policy->primaryRange.min, policy->primaryRange.max); + + if (!signals.touch && signals.idle && !(primaryRangeIsSingleRate && hasExplicitVoteLayers)) { + ALOGV("Idle"); + return {rankRefreshRates(activeMode.getGroup(), RefreshRateOrder::Ascending), + GlobalSignals{.idle = true}}; + } + + if (layers.empty() || noVoteLayers == layers.size()) { + ALOGV("No layers with votes"); + return {rankRefreshRates(anchorGroup, RefreshRateOrder::Descending), kNoSignals}; + } + + // Only if all layers want Min we should return Min + if (noVoteLayers + minVoteLayers == layers.size()) { + ALOGV("All layers Min"); + return {rankRefreshRates(activeMode.getGroup(), RefreshRateOrder::Ascending), kNoSignals}; + } + + // Find the best refresh rate based on score + std::vector scores; + scores.reserve(mAppRequestRefreshRates.size()); + + for (const DisplayModeIterator modeIt : mAppRequestRefreshRates) { + scores.emplace_back(RefreshRateScore{modeIt, 0.0f}); + } + + for (const auto& layer : layers) { + ALOGV("Calculating score for %s (%s, weight %.2f, desired %.2f) ", layer.name.c_str(), + ftl::enum_string(layer.vote).c_str(), layer.weight, + layer.desiredRefreshRate.getValue()); + if (layer.vote == LayerVoteType::NoVote || layer.vote == LayerVoteType::Min) { + continue; + } + + const auto weight = layer.weight; + + for (auto& [modeIt, overallScore, fixedRateBelowThresholdLayersScore] : scores) { + const auto& [id, mode] = *modeIt; + const bool isSeamlessSwitch = mode->getGroup() == activeMode.getGroup(); + + if (layer.seamlessness == Seamlessness::OnlySeamless && !isSeamlessSwitch) { + ALOGV("%s ignores %s to avoid non-seamless switch. Current mode = %s", + formatLayerInfo(layer, weight).c_str(), to_string(*mode).c_str(), + to_string(activeMode).c_str()); + continue; + } + + if (layer.seamlessness == Seamlessness::SeamedAndSeamless && !isSeamlessSwitch && + !layer.focused) { + ALOGV("%s ignores %s because it's not focused and the switch is going to be seamed." + " Current mode = %s", + formatLayerInfo(layer, weight).c_str(), to_string(*mode).c_str(), + to_string(activeMode).c_str()); + continue; + } + + // Layers with default seamlessness vote for the current mode group if + // there are layers with seamlessness=SeamedAndSeamless and for the default + // mode group otherwise. In second case, if the current mode group is different + // from the default, this means a layer with seamlessness=SeamedAndSeamless has just + // disappeared. + const bool isInPolicyForDefault = mode->getGroup() == anchorGroup; + if (layer.seamlessness == Seamlessness::Default && !isInPolicyForDefault) { + ALOGV("%s ignores %s. Current mode = %s", formatLayerInfo(layer, weight).c_str(), + to_string(*mode).c_str(), to_string(activeMode).c_str()); + continue; + } + + const bool inPrimaryRange = policy->primaryRange.includes(mode->getFps()); + if ((primaryRangeIsSingleRate || !inPrimaryRange) && + !(layer.focused && + (layer.vote == LayerVoteType::ExplicitDefault || + layer.vote == LayerVoteType::ExplicitExact))) { + // Only focused layers with ExplicitDefault frame rate settings are allowed to score + // refresh rates outside the primary range. + continue; + } + + const float layerScore = + calculateLayerScoreLocked(layer, mode->getFps(), isSeamlessSwitch); + const float weightedLayerScore = weight * layerScore; + + // Layer with fixed source has a special consideration which depends on the + // mConfig.frameRateMultipleThreshold. We don't want these layers to score + // refresh rates above the threshold, but we also don't want to favor the lower + // ones by having a greater number of layers scoring them. Instead, we calculate + // the score independently for these layers and later decide which + // refresh rates to add it. For example, desired 24 fps with 120 Hz threshold should not + // score 120 Hz, but desired 60 fps should contribute to the score. + const bool fixedSourceLayer = [](LayerVoteType vote) { + switch (vote) { + case LayerVoteType::ExplicitExactOrMultiple: + case LayerVoteType::Heuristic: + return true; + case LayerVoteType::NoVote: + case LayerVoteType::Min: + case LayerVoteType::Max: + case LayerVoteType::ExplicitDefault: + case LayerVoteType::ExplicitExact: + return false; + } + }(layer.vote); + const bool layerBelowThreshold = mConfig.frameRateMultipleThreshold != 0 && + layer.desiredRefreshRate < + Fps::fromValue(mConfig.frameRateMultipleThreshold / 2); + if (fixedSourceLayer && layerBelowThreshold) { + const bool modeAboveThreshold = + mode->getFps() >= Fps::fromValue(mConfig.frameRateMultipleThreshold); + if (modeAboveThreshold) { + ALOGV("%s gives %s fixed source (above threshold) score of %.4f", + formatLayerInfo(layer, weight).c_str(), to_string(mode->getFps()).c_str(), + layerScore); + fixedRateBelowThresholdLayersScore.modeAboveThreshold += weightedLayerScore; + } else { + ALOGV("%s gives %s fixed source (below threshold) score of %.4f", + formatLayerInfo(layer, weight).c_str(), to_string(mode->getFps()).c_str(), + layerScore); + fixedRateBelowThresholdLayersScore.modeBelowThreshold += weightedLayerScore; + } + } else { + ALOGV("%s gives %s score of %.4f", formatLayerInfo(layer, weight).c_str(), + to_string(mode->getFps()).c_str(), layerScore); + overallScore += weightedLayerScore; + } + } + } + + // We want to find the best refresh rate without the fixed source layers, + // so we could know whether we should add the modeAboveThreshold scores or not. + // If the best refresh rate is already above the threshold, it means that + // some non-fixed source layers already scored it, so we can just add the score + // for all fixed source layers, even the ones that are above the threshold. + const bool maxScoreAboveThreshold = [&] { + if (mConfig.frameRateMultipleThreshold == 0 || scores.empty()) { + return false; + } + + const auto maxScoreIt = + std::max_element(scores.begin(), scores.end(), + [](RefreshRateScore max, RefreshRateScore current) { + const auto& [modeIt, overallScore, _] = current; + return overallScore > max.overallScore; + }); + ALOGV("%s is the best refresh rate without fixed source layers. It is %s the threshold for " + "refresh rate multiples", + to_string(maxScoreIt->modeIt->second->getFps()).c_str(), + maxScoreAboveThreshold ? "above" : "below"); + return maxScoreIt->modeIt->second->getFps() >= + Fps::fromValue(mConfig.frameRateMultipleThreshold); + }(); + + // Now we can add the fixed rate layers score + for (auto& [modeIt, overallScore, fixedRateBelowThresholdLayersScore] : scores) { + overallScore += fixedRateBelowThresholdLayersScore.modeBelowThreshold; + if (maxScoreAboveThreshold) { + overallScore += fixedRateBelowThresholdLayersScore.modeAboveThreshold; + } + ALOGV("%s adjusted overallScore is %.4f", to_string(modeIt->second->getFps()).c_str(), + overallScore); + } + + // Now that we scored all the refresh rates we need to pick the one that got the highest + // overallScore. Sort the scores based on their overallScore in descending order of priority. + const RefreshRateOrder refreshRateOrder = + maxVoteLayers > 0 ? RefreshRateOrder::Descending : RefreshRateOrder::Ascending; + std::sort(scores.begin(), scores.end(), + RefreshRateScoreComparator{.refreshRateOrder = refreshRateOrder}); + + RefreshRateRanking ranking; + ranking.reserve(scores.size()); + + std::transform(scores.begin(), scores.end(), back_inserter(ranking), + [](const RefreshRateScore& score) { + return ScoredRefreshRate{score.modeIt->second, score.overallScore}; + }); + + const bool noLayerScore = std::all_of(scores.begin(), scores.end(), [](RefreshRateScore score) { + return score.overallScore == 0; + }); + + if (primaryRangeIsSingleRate) { + // If we never scored any layers, then choose the rate from the primary + // range instead of picking a random score from the app range. + if (noLayerScore) { + ALOGV("Layers not scored"); + return {rankRefreshRates(anchorGroup, RefreshRateOrder::Descending), kNoSignals}; + } else { + return {ranking, kNoSignals}; + } + } + + // Consider the touch event if there are no ExplicitDefault layers. ExplicitDefault are mostly + // interactive (as opposed to ExplicitExactOrMultiple) and therefore if those posted an explicit + // vote we should not change it if we get a touch event. Only apply touch boost if it will + // actually increase the refresh rate over the normal selection. + const bool touchBoostForExplicitExact = [&] { + if (mSupportsFrameRateOverrideByContent) { + // Enable touch boost if there are other layers besides exact + return explicitExact + noVoteLayers != layers.size(); + } else { + // Enable touch boost if there are no exact layers + return explicitExact == 0; + } + }(); + + const auto touchRefreshRates = rankRefreshRates(anchorGroup, RefreshRateOrder::Descending); + + using fps_approx_ops::operator<; + + if (signals.touch && explicitDefaultVoteLayers == 0 && touchBoostForExplicitExact && + scores.front().modeIt->second->getFps() < touchRefreshRates.front().modePtr->getFps()) { + ALOGV("Touch Boost"); + return {touchRefreshRates, GlobalSignals{.touch = true}}; + } + + // If we never scored any layers, and we don't favor high refresh rates, prefer to stay with the + // current config + if (noLayerScore && refreshRateOrder == RefreshRateOrder::Ascending) { + const auto preferredDisplayMode = activeMode.getId(); + return {rankRefreshRates(anchorGroup, RefreshRateOrder::Ascending, preferredDisplayMode), + kNoSignals}; + } + + return {ranking, kNoSignals}; +} + +using LayerRequirementPtrs = std::vector; +using PerUidLayerRequirements = std::unordered_map; + +PerUidLayerRequirements groupLayersByUid( + const std::vector& layers) { + PerUidLayerRequirements layersByUid; + for (const auto& layer : layers) { + const auto it = layersByUid.emplace(layer.ownerUid, LayerRequirementPtrs()).first; + auto& layersWithSameUid = it->second; + layersWithSameUid.push_back(&layer); + } + + // Remove uids that can't have a frame rate override + for (auto it = layersByUid.begin(); it != layersByUid.end();) { + const auto& layersWithSameUid = it->second; + bool skipUid = false; + for (const auto& layer : layersWithSameUid) { + using LayerVoteType = RefreshRateSelector::LayerVoteType; + + if (layer->vote == LayerVoteType::Max || layer->vote == LayerVoteType::Heuristic) { + skipUid = true; + break; + } + } + if (skipUid) { + it = layersByUid.erase(it); + } else { + ++it; + } + } + + return layersByUid; +} + +auto RefreshRateSelector::getFrameRateOverrides(const std::vector& layers, + Fps displayRefreshRate, + GlobalSignals globalSignals) const + -> UidToFrameRateOverride { + ATRACE_CALL(); + + ALOGV("%s: %zu layers", __func__, layers.size()); + + std::lock_guard lock(mLock); + + std::vector scores; + scores.reserve(mDisplayModes.size()); + + for (auto it = mDisplayModes.begin(); it != mDisplayModes.end(); ++it) { + scores.emplace_back(RefreshRateScore{it, 0.0f}); + } + + std::sort(scores.begin(), scores.end(), [](const auto& lhs, const auto& rhs) { + const auto& mode1 = lhs.modeIt->second; + const auto& mode2 = rhs.modeIt->second; + return isStrictlyLess(mode1->getFps(), mode2->getFps()); + }); + + const auto layersByUid = groupLayersByUid(layers); + UidToFrameRateOverride frameRateOverrides; + for (const auto& [uid, layersWithSameUid] : layersByUid) { + // Layers with ExplicitExactOrMultiple expect touch boost + const bool hasExplicitExactOrMultiple = + std::any_of(layersWithSameUid.cbegin(), layersWithSameUid.cend(), + [](const auto& layer) { + return layer->vote == LayerVoteType::ExplicitExactOrMultiple; + }); + + if (globalSignals.touch && hasExplicitExactOrMultiple) { + continue; + } + + for (auto& [_, score, _1] : scores) { + score = 0; + } + + for (const auto& layer : layersWithSameUid) { + if (layer->vote == LayerVoteType::NoVote || layer->vote == LayerVoteType::Min) { + continue; + } + + LOG_ALWAYS_FATAL_IF(layer->vote != LayerVoteType::ExplicitDefault && + layer->vote != LayerVoteType::ExplicitExactOrMultiple && + layer->vote != LayerVoteType::ExplicitExact); + for (auto& [modeIt, score, _] : scores) { + constexpr bool isSeamlessSwitch = true; + const auto layerScore = calculateLayerScoreLocked(*layer, modeIt->second->getFps(), + isSeamlessSwitch); + score += layer->weight * layerScore; + } + } + + // We just care about the refresh rates which are a divisor of the + // display refresh rate + const auto it = std::remove_if(scores.begin(), scores.end(), [&](RefreshRateScore score) { + const auto& [id, mode] = *score.modeIt; + return getFrameRateDivisor(displayRefreshRate, mode->getFps()) == 0; + }); + scores.erase(it, scores.end()); + + // If we never scored any layers, we don't have a preferred frame rate + if (std::all_of(scores.begin(), scores.end(), + [](RefreshRateScore score) { return score.overallScore == 0; })) { + continue; + } + + // Now that we scored all the refresh rates we need to pick the lowest refresh rate + // that got the highest score. + const DisplayModePtr& bestRefreshRate = + std::min_element(scores.begin(), scores.end(), + RefreshRateScoreComparator{.refreshRateOrder = + RefreshRateOrder::Ascending}) + ->modeIt->second; + frameRateOverrides.emplace(uid, bestRefreshRate->getFps()); + } + + return frameRateOverrides; +} + +std::optional RefreshRateSelector::onKernelTimerChanged( + std::optional desiredActiveModeId, bool timerExpired) const { + std::lock_guard lock(mLock); + + const DisplayModePtr& current = desiredActiveModeId + ? mDisplayModes.get(*desiredActiveModeId)->get() + : getActiveModeItLocked()->second; + + const DisplayModePtr& min = mMinRefreshRateModeIt->second; + if (current == min) { + return {}; + } + + const auto& mode = timerExpired ? min : current; + return mode->getFps(); +} + +const DisplayModePtr& RefreshRateSelector::getMinRefreshRateByPolicyLocked() const { + const auto& activeMode = *getActiveModeItLocked()->second; + + for (const DisplayModeIterator modeIt : mPrimaryRefreshRates) { + const auto& mode = modeIt->second; + if (activeMode.getGroup() == mode->getGroup()) { + return mode; + } + } + + ALOGE("Can't find min refresh rate by policy with the same mode group as the current mode %s", + to_string(activeMode).c_str()); + + // Default to the lowest refresh rate. + return mPrimaryRefreshRates.front()->second; +} + +const DisplayModePtr& RefreshRateSelector::getMaxRefreshRateByPolicyLocked(int anchorGroup) const { + for (auto it = mPrimaryRefreshRates.rbegin(); it != mPrimaryRefreshRates.rend(); ++it) { + const auto& mode = (*it)->second; + if (anchorGroup == mode->getGroup()) { + return mode; + } + } + + ALOGE("Can't find max refresh rate by policy with the same group %d", anchorGroup); + + // Default to the highest refresh rate. + return mPrimaryRefreshRates.back()->second; +} + +auto RefreshRateSelector::rankRefreshRates( + std::optional anchorGroupOpt, RefreshRateOrder refreshRateOrder, + std::optional preferredDisplayModeOpt) const -> RefreshRateRanking { + std::deque ranking; + + const auto rankRefreshRate = [&](DisplayModeIterator it) REQUIRES(mLock) { + const auto& mode = it->second; + if (anchorGroupOpt && mode->getGroup() != anchorGroupOpt) { + return; + } + + float score = calculateRefreshRateScoreForFps(mode->getFps()); + const bool inverseScore = (refreshRateOrder == RefreshRateOrder::Ascending); + if (inverseScore) { + score = 1.0f / score; + } + if (preferredDisplayModeOpt) { + if (*preferredDisplayModeOpt == mode->getId()) { + constexpr float kScore = std::numeric_limits::max(); + ranking.push_front(ScoredRefreshRate{mode, kScore}); + return; + } + constexpr float kNonPreferredModePenalty = 0.95f; + score *= kNonPreferredModePenalty; + } + ranking.push_back(ScoredRefreshRate{mode, score}); + }; + + if (refreshRateOrder == RefreshRateOrder::Ascending) { + std::for_each(mPrimaryRefreshRates.begin(), mPrimaryRefreshRates.end(), rankRefreshRate); + } else { + std::for_each(mPrimaryRefreshRates.rbegin(), mPrimaryRefreshRates.rend(), rankRefreshRate); + } + + if (!ranking.empty() || !anchorGroupOpt) { + return {ranking.begin(), ranking.end()}; + } + + ALOGW("Can't find %s refresh rate by policy with the same mode group" + " as the mode group %d", + refreshRateOrder == RefreshRateOrder::Ascending ? "min" : "max", anchorGroupOpt.value()); + + constexpr std::optional kNoAnchorGroup = std::nullopt; + return rankRefreshRates(kNoAnchorGroup, refreshRateOrder, preferredDisplayModeOpt); +} + +DisplayModePtr RefreshRateSelector::getActiveModePtr() const { + std::lock_guard lock(mLock); + return getActiveModeItLocked()->second; +} + +const DisplayMode& RefreshRateSelector::getActiveMode() const { + // Reads from kMainThreadContext do not require mLock. + ftl::FakeGuard guard(mLock); + return *mActiveModeIt->second; +} + +DisplayModeIterator RefreshRateSelector::getActiveModeItLocked() const { + // Reads under mLock do not require kMainThreadContext. + return FTL_FAKE_GUARD(kMainThreadContext, mActiveModeIt); +} + +void RefreshRateSelector::setActiveModeId(DisplayModeId modeId) { + std::lock_guard lock(mLock); + + // Invalidate the cached invocation to getRankedRefreshRates. This forces + // the refresh rate to be recomputed on the next call to getRankedRefreshRates. + mGetRankedRefreshRatesCache.reset(); + + mActiveModeIt = mDisplayModes.find(modeId); + LOG_ALWAYS_FATAL_IF(mActiveModeIt == mDisplayModes.end()); +} + +RefreshRateSelector::RefreshRateSelector(DisplayModes modes, DisplayModeId activeModeId, + Config config) + : mKnownFrameRates(constructKnownFrameRates(modes)), mConfig(config) { + initializeIdleTimer(); + FTL_FAKE_GUARD(kMainThreadContext, updateDisplayModes(std::move(modes), activeModeId)); +} + +void RefreshRateSelector::initializeIdleTimer() { + if (mConfig.idleTimerTimeout > 0ms) { + mIdleTimer.emplace( + "IdleTimer", mConfig.idleTimerTimeout, + [this] { + std::scoped_lock lock(mIdleTimerCallbacksMutex); + if (const auto callbacks = getIdleTimerCallbacks()) { + callbacks->onReset(); + } + }, + [this] { + std::scoped_lock lock(mIdleTimerCallbacksMutex); + if (const auto callbacks = getIdleTimerCallbacks()) { + callbacks->onExpired(); + } + }); + } +} + +void RefreshRateSelector::updateDisplayModes(DisplayModes modes, DisplayModeId activeModeId) { + std::lock_guard lock(mLock); + + // Invalidate the cached invocation to getRankedRefreshRates. This forces + // the refresh rate to be recomputed on the next call to getRankedRefreshRates. + mGetRankedRefreshRatesCache.reset(); + + mDisplayModes = std::move(modes); + mActiveModeIt = mDisplayModes.find(activeModeId); + LOG_ALWAYS_FATAL_IF(mActiveModeIt == mDisplayModes.end()); + + const auto sortedModes = + sortByRefreshRate(mDisplayModes, [](const DisplayMode&) { return true; }); + mMinRefreshRateModeIt = sortedModes.front(); + mMaxRefreshRateModeIt = sortedModes.back(); + + // Reset the policy because the old one may no longer be valid. + mDisplayManagerPolicy = {}; + mDisplayManagerPolicy.defaultMode = activeModeId; + + mSupportsFrameRateOverrideByContent = + mConfig.enableFrameRateOverride && canModesSupportFrameRateOverride(sortedModes); + + constructAvailableRefreshRates(); +} + +bool RefreshRateSelector::isPolicyValidLocked(const Policy& policy) const { + // defaultMode must be a valid mode, and within the given refresh rate range. + if (const auto mode = mDisplayModes.get(policy.defaultMode)) { + if (!policy.primaryRange.includes(mode->get()->getFps())) { + ALOGE("Default mode is not in the primary range."); + return false; + } + } else { + ALOGE("Default mode is not found."); + return false; + } + + using namespace fps_approx_ops; + return policy.appRequestRange.min <= policy.primaryRange.min && + policy.appRequestRange.max >= policy.primaryRange.max; +} + +auto RefreshRateSelector::setPolicy(const PolicyVariant& policy) -> SetPolicyResult { + Policy oldPolicy; + { + std::lock_guard lock(mLock); + oldPolicy = *getCurrentPolicyLocked(); + + const bool valid = ftl::match( + policy, + [this](const auto& policy) { + ftl::FakeGuard guard(mLock); + if (!isPolicyValidLocked(policy)) { + ALOGE("Invalid policy: %s", policy.toString().c_str()); + return false; + } + + using T = std::decay_t; + + if constexpr (std::is_same_v) { + mDisplayManagerPolicy = policy; + } else { + static_assert(std::is_same_v); + mOverridePolicy = policy; + } + return true; + }, + [this](NoOverridePolicy) { + ftl::FakeGuard guard(mLock); + mOverridePolicy.reset(); + return true; + }); + + if (!valid) { + return SetPolicyResult::Invalid; + } + + mGetRankedRefreshRatesCache.reset(); + + if (*getCurrentPolicyLocked() == oldPolicy) { + return SetPolicyResult::Unchanged; + } + constructAvailableRefreshRates(); + } + + const auto displayId = getActiveMode().getPhysicalDisplayId(); + const unsigned numModeChanges = std::exchange(mNumModeSwitchesInPolicy, 0u); + + ALOGI("Display %s policy changed\n" + "Previous: %s\n" + "Current: %s\n" + "%u mode changes were performed under the previous policy", + to_string(displayId).c_str(), oldPolicy.toString().c_str(), toString(policy).c_str(), + numModeChanges); + + return SetPolicyResult::Changed; +} + +auto RefreshRateSelector::getCurrentPolicyLocked() const -> const Policy* { + return mOverridePolicy ? &mOverridePolicy.value() : &mDisplayManagerPolicy; +} + +auto RefreshRateSelector::getCurrentPolicy() const -> Policy { + std::lock_guard lock(mLock); + return *getCurrentPolicyLocked(); +} + +auto RefreshRateSelector::getDisplayManagerPolicy() const -> Policy { + std::lock_guard lock(mLock); + return mDisplayManagerPolicy; +} + +bool RefreshRateSelector::isModeAllowed(DisplayModeId modeId) const { + std::lock_guard lock(mLock); + return std::any_of(mAppRequestRefreshRates.begin(), mAppRequestRefreshRates.end(), + [modeId](DisplayModeIterator modeIt) { + return modeIt->second->getId() == modeId; + }); +} + +void RefreshRateSelector::constructAvailableRefreshRates() { + // Filter modes based on current policy and sort on refresh rate. + const Policy* policy = getCurrentPolicyLocked(); + ALOGV("%s: %s ", __func__, policy->toString().c_str()); + + const auto& defaultMode = mDisplayModes.get(policy->defaultMode)->get(); + + const auto filterRefreshRates = [&](FpsRange range, const char* rangeName) REQUIRES(mLock) { + const auto filter = [&](const DisplayMode& mode) { + return mode.getResolution() == defaultMode->getResolution() && + mode.getDpi() == defaultMode->getDpi() && + (policy->allowGroupSwitching || mode.getGroup() == defaultMode->getGroup()) && + range.includes(mode.getFps()); + }; + + const auto modes = sortByRefreshRate(mDisplayModes, filter); + LOG_ALWAYS_FATAL_IF(modes.empty(), "No matching modes for %s range %s", rangeName, + to_string(range).c_str()); + + const auto stringifyModes = [&] { + std::string str; + for (const auto modeIt : modes) { + str += to_string(modeIt->second->getFps()); + str.push_back(' '); + } + return str; + }; + ALOGV("%s refresh rates: %s", rangeName, stringifyModes().c_str()); + + return modes; + }; + + mPrimaryRefreshRates = filterRefreshRates(policy->primaryRange, "primary"); + mAppRequestRefreshRates = filterRefreshRates(policy->appRequestRange, "app request"); +} + +Fps RefreshRateSelector::findClosestKnownFrameRate(Fps frameRate) const { + using namespace fps_approx_ops; + + if (frameRate <= mKnownFrameRates.front()) { + return mKnownFrameRates.front(); + } + + if (frameRate >= mKnownFrameRates.back()) { + return mKnownFrameRates.back(); + } + + auto lowerBound = std::lower_bound(mKnownFrameRates.begin(), mKnownFrameRates.end(), frameRate, + isStrictlyLess); + + const auto distance1 = std::abs(frameRate.getValue() - lowerBound->getValue()); + const auto distance2 = std::abs(frameRate.getValue() - std::prev(lowerBound)->getValue()); + return distance1 < distance2 ? *lowerBound : *std::prev(lowerBound); +} + +auto RefreshRateSelector::getIdleTimerAction() const -> KernelIdleTimerAction { + std::lock_guard lock(mLock); + + const Fps deviceMinFps = mMinRefreshRateModeIt->second->getFps(); + const DisplayModePtr& minByPolicy = getMinRefreshRateByPolicyLocked(); + + // Kernel idle timer will set the refresh rate to the device min. If DisplayManager says that + // the min allowed refresh rate is higher than the device min, we do not want to enable the + // timer. + if (isStrictlyLess(deviceMinFps, minByPolicy->getFps())) { + return KernelIdleTimerAction::TurnOff; + } + + const DisplayModePtr& maxByPolicy = + getMaxRefreshRateByPolicyLocked(getActiveModeItLocked()->second->getGroup()); + if (minByPolicy == maxByPolicy) { + // Turn on the timer when the min of the primary range is below the device min. + if (const Policy* currentPolicy = getCurrentPolicyLocked(); + isApproxLess(currentPolicy->primaryRange.min, deviceMinFps)) { + return KernelIdleTimerAction::TurnOn; + } + return KernelIdleTimerAction::TurnOff; + } + + // Turn on the timer in all other cases. + return KernelIdleTimerAction::TurnOn; +} + +int RefreshRateSelector::getFrameRateDivisor(Fps displayRefreshRate, Fps layerFrameRate) { + // This calculation needs to be in sync with the java code + // in DisplayManagerService.getDisplayInfoForFrameRateOverride + + // The threshold must be smaller than 0.001 in order to differentiate + // between the fractional pairs (e.g. 59.94 and 60). + constexpr float kThreshold = 0.0009f; + const auto numPeriods = displayRefreshRate.getValue() / layerFrameRate.getValue(); + const auto numPeriodsRounded = std::round(numPeriods); + if (std::abs(numPeriods - numPeriodsRounded) > kThreshold) { + return 0; + } + + return static_cast(numPeriodsRounded); +} + +bool RefreshRateSelector::isFractionalPairOrMultiple(Fps smaller, Fps bigger) { + if (isStrictlyLess(bigger, smaller)) { + return isFractionalPairOrMultiple(bigger, smaller); + } + + const auto multiplier = std::round(bigger.getValue() / smaller.getValue()); + constexpr float kCoef = 1000.f / 1001.f; + return isApproxEqual(bigger, Fps::fromValue(smaller.getValue() * multiplier / kCoef)) || + isApproxEqual(bigger, Fps::fromValue(smaller.getValue() * multiplier * kCoef)); +} + +void RefreshRateSelector::dump(utils::Dumper& dumper) const { + using namespace std::string_view_literals; + + std::lock_guard lock(mLock); + + const auto activeModeId = getActiveModeItLocked()->first; + dumper.dump("activeModeId"sv, std::to_string(activeModeId.value())); + + dumper.dump("displayModes"sv); + { + utils::Dumper::Indent indent(dumper); + for (const auto& [id, mode] : mDisplayModes) { + dumper.dump({}, to_string(*mode)); + } + } + + dumper.dump("displayManagerPolicy"sv, mDisplayManagerPolicy.toString()); + + if (const Policy& currentPolicy = *getCurrentPolicyLocked(); + mOverridePolicy && currentPolicy != mDisplayManagerPolicy) { + dumper.dump("overridePolicy"sv, currentPolicy.toString()); + } + + dumper.dump("supportsFrameRateOverrideByContent"sv, mSupportsFrameRateOverrideByContent); + + std::string idleTimer; + if (mIdleTimer) { + idleTimer = mIdleTimer->dump(); + } else { + idleTimer = "off"sv; + } + + if (const auto controller = mConfig.kernelIdleTimerController) { + base::StringAppendF(&idleTimer, " (kernel via %s)", ftl::enum_string(*controller).c_str()); + } else { + idleTimer += " (platform)"sv; + } + + dumper.dump("idleTimer"sv, idleTimer); +} + +std::chrono::milliseconds RefreshRateSelector::getIdleTimerTimeout() { + return mConfig.idleTimerTimeout; +} + +} // namespace android::scheduler + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic pop // ignored "-Wextra" diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.h b/services/surfaceflinger/Scheduler/RefreshRateSelector.h new file mode 100644 index 0000000000..bff16d3010 --- /dev/null +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.h @@ -0,0 +1,473 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "DisplayHardware/DisplayMode.h" +#include "DisplayHardware/HWComposer.h" +#include "Scheduler/OneShotTimer.h" +#include "Scheduler/StrongTyping.h" +#include "ThreadContext.h" +#include "Utils/Dumper.h" + +namespace android::scheduler { + +using namespace std::chrono_literals; + +enum class DisplayModeEvent : unsigned { None = 0b0, Changed = 0b1 }; + +inline DisplayModeEvent operator|(DisplayModeEvent lhs, DisplayModeEvent rhs) { + using T = std::underlying_type_t; + return static_cast(static_cast(lhs) | static_cast(rhs)); +} + +using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride; + +// Selects the refresh rate of a display by ranking its `DisplayModes` in accordance with +// the DisplayManager (or override) `Policy`, the `LayerRequirement` of each active layer, +// and `GlobalSignals`. +class RefreshRateSelector { +public: + // Margin used when matching refresh rates to the content desired ones. + static constexpr nsecs_t MARGIN_FOR_PERIOD_CALCULATION = + std::chrono::nanoseconds(800us).count(); + + class Policy { + static constexpr int kAllowGroupSwitchingDefault = false; + + public: + // The default mode, used to ensure we only initiate display mode switches within the + // same mode group as defaultMode's group. + DisplayModeId defaultMode; + // Whether or not we switch mode groups to get the best frame rate. + bool allowGroupSwitching = kAllowGroupSwitchingDefault; + // The primary refresh rate range represents display manager's general guidance on the + // display modes we'll consider when switching refresh rates. Unless we get an explicit + // signal from an app, we should stay within this range. + FpsRange primaryRange; + // The app request refresh rate range allows us to consider more display modes when + // switching refresh rates. Although we should generally stay within the primary range, + // specific considerations, such as layer frame rate settings specified via the + // setFrameRate() api, may cause us to go outside the primary range. We never go outside the + // app request range. The app request range will be greater than or equal to the primary + // refresh rate range, never smaller. + FpsRange appRequestRange; + + Policy() = default; + + Policy(DisplayModeId defaultMode, FpsRange range) + : Policy(defaultMode, kAllowGroupSwitchingDefault, range, range) {} + + Policy(DisplayModeId defaultMode, bool allowGroupSwitching, FpsRange range) + : Policy(defaultMode, allowGroupSwitching, range, range) {} + + Policy(DisplayModeId defaultMode, FpsRange primaryRange, FpsRange appRequestRange) + : Policy(defaultMode, kAllowGroupSwitchingDefault, primaryRange, appRequestRange) {} + + Policy(DisplayModeId defaultMode, bool allowGroupSwitching, FpsRange primaryRange, + FpsRange appRequestRange) + : defaultMode(defaultMode), + allowGroupSwitching(allowGroupSwitching), + primaryRange(primaryRange), + appRequestRange(appRequestRange) {} + + bool operator==(const Policy& other) const { + using namespace fps_approx_ops; + return defaultMode == other.defaultMode && primaryRange == other.primaryRange && + appRequestRange == other.appRequestRange && + allowGroupSwitching == other.allowGroupSwitching; + } + + bool operator!=(const Policy& other) const { return !(*this == other); } + std::string toString() const; + }; + + enum class SetPolicyResult { Invalid, Unchanged, Changed }; + + // We maintain the display manager policy and the override policy separately. The override + // policy is used by CTS tests to get a consistent device state for testing. While the override + // policy is set, it takes precedence over the display manager policy. Once the override policy + // is cleared, we revert to using the display manager policy. + struct DisplayManagerPolicy : Policy { + using Policy::Policy; + }; + + struct OverridePolicy : Policy { + using Policy::Policy; + }; + + struct NoOverridePolicy {}; + + using PolicyVariant = std::variant; + + SetPolicyResult setPolicy(const PolicyVariant&) EXCLUDES(mLock) REQUIRES(kMainThreadContext); + + void onModeChangeInitiated() REQUIRES(kMainThreadContext) { mNumModeSwitchesInPolicy++; } + + // Gets the current policy, which will be the override policy if active, and the display manager + // policy otherwise. + Policy getCurrentPolicy() const EXCLUDES(mLock); + // Gets the display manager policy, regardless of whether an override policy is active. + Policy getDisplayManagerPolicy() const EXCLUDES(mLock); + + // Returns true if mode is allowed by the current policy. + bool isModeAllowed(DisplayModeId) const EXCLUDES(mLock); + + // Describes the different options the layer voted for refresh rate + enum class LayerVoteType { + NoVote, // Doesn't care about the refresh rate + Min, // Minimal refresh rate available + Max, // Maximal refresh rate available + Heuristic, // Specific refresh rate that was calculated by platform using a heuristic + ExplicitDefault, // Specific refresh rate that was provided by the app with Default + // compatibility + ExplicitExactOrMultiple, // Specific refresh rate that was provided by the app with + // ExactOrMultiple compatibility + ExplicitExact, // Specific refresh rate that was provided by the app with + // Exact compatibility + + ftl_last = ExplicitExact + }; + + // Captures the layer requirements for a refresh rate. This will be used to determine the + // display refresh rate. + struct LayerRequirement { + // Layer's name. Used for debugging purposes. + std::string name; + // Layer's owner uid + uid_t ownerUid = static_cast(-1); + // Layer vote type. + LayerVoteType vote = LayerVoteType::NoVote; + // Layer's desired refresh rate, if applicable. + Fps desiredRefreshRate; + // If a seamless mode switch is required. + Seamlessness seamlessness = Seamlessness::Default; + // Layer's weight in the range of [0, 1]. The higher the weight the more impact this layer + // would have on choosing the refresh rate. + float weight = 0.0f; + // Whether layer is in focus or not based on WindowManager's state + bool focused = false; + + bool operator==(const LayerRequirement& other) const { + return name == other.name && vote == other.vote && + isApproxEqual(desiredRefreshRate, other.desiredRefreshRate) && + seamlessness == other.seamlessness && weight == other.weight && + focused == other.focused; + } + + bool operator!=(const LayerRequirement& other) const { return !(*this == other); } + }; + + // Global state describing signals that affect refresh rate choice. + struct GlobalSignals { + // Whether the user touched the screen recently. Used to apply touch boost. + bool touch = false; + // True if the system hasn't seen any buffers posted to layers recently. + bool idle = false; + // Whether the display is about to be powered on, or has been in PowerMode::ON + // within the timeout of DisplayPowerTimer. + bool powerOnImminent = false; + + bool operator==(GlobalSignals other) const { + return touch == other.touch && idle == other.idle && + powerOnImminent == other.powerOnImminent; + } + + auto toString() const { + return ftl::Concat("{touch=", touch, ", idle=", idle, + ", powerOnImminent=", powerOnImminent, '}'); + } + }; + + struct ScoredRefreshRate { + DisplayModePtr modePtr; + float score = 0.0f; + + bool operator==(const ScoredRefreshRate& other) const { + return modePtr == other.modePtr && score == other.score; + } + + static bool scoresEqual(float lhs, float rhs) { + constexpr float kEpsilon = 0.0001f; + return std::abs(lhs - rhs) <= kEpsilon; + } + + struct DescendingScore { + bool operator()(const ScoredRefreshRate& lhs, const ScoredRefreshRate& rhs) const { + return lhs.score > rhs.score && !scoresEqual(lhs.score, rhs.score); + } + }; + }; + + using RefreshRateRanking = std::vector; + + struct RankedRefreshRates { + RefreshRateRanking ranking; // Ordered by descending score. + GlobalSignals consideredSignals; + + bool operator==(const RankedRefreshRates& other) const { + return ranking == other.ranking && consideredSignals == other.consideredSignals; + } + }; + + RankedRefreshRates getRankedRefreshRates(const std::vector&, + GlobalSignals) const EXCLUDES(mLock); + + FpsRange getSupportedRefreshRateRange() const EXCLUDES(mLock) { + std::lock_guard lock(mLock); + return {mMinRefreshRateModeIt->second->getFps(), mMaxRefreshRateModeIt->second->getFps()}; + } + + std::optional onKernelTimerChanged(std::optional desiredActiveModeId, + bool timerExpired) const EXCLUDES(mLock); + + void setActiveModeId(DisplayModeId) EXCLUDES(mLock) REQUIRES(kMainThreadContext); + + // See mActiveModeIt for thread safety. + DisplayModePtr getActiveModePtr() const EXCLUDES(mLock); + const DisplayMode& getActiveMode() const REQUIRES(kMainThreadContext); + + // Returns a known frame rate that is the closest to frameRate + Fps findClosestKnownFrameRate(Fps frameRate) const; + + enum class KernelIdleTimerController { Sysprop, HwcApi, ftl_last = HwcApi }; + + // Configuration flags. + struct Config { + bool enableFrameRateOverride = false; + + // Specifies the upper refresh rate threshold (inclusive) for layer vote types of multiple + // or heuristic, such that refresh rates higher than this value will not be voted for. 0 if + // no threshold is set. + int frameRateMultipleThreshold = 0; + + // The Idle Timer timeout. 0 timeout means no idle timer. + std::chrono::milliseconds idleTimerTimeout = 0ms; + + // The controller representing how the kernel idle timer will be configured + // either on the HWC api or sysprop. + std::optional kernelIdleTimerController; + }; + + RefreshRateSelector(DisplayModes, DisplayModeId activeModeId, + Config config = {.enableFrameRateOverride = false, + .frameRateMultipleThreshold = 0, + .idleTimerTimeout = 0ms, + .kernelIdleTimerController = {}}); + + RefreshRateSelector(const RefreshRateSelector&) = delete; + RefreshRateSelector& operator=(const RefreshRateSelector&) = delete; + + // Returns whether switching modes (refresh rate or resolution) is possible. + // TODO(b/158780872): Consider HAL support, and skip frame rate detection if the modes only + // differ in resolution. + bool canSwitch() const EXCLUDES(mLock) { + std::lock_guard lock(mLock); + return mDisplayModes.size() > 1; + } + + // Class to enumerate options around toggling the kernel timer on and off. + enum class KernelIdleTimerAction { + TurnOff, // Turn off the idle timer. + TurnOn // Turn on the idle timer. + }; + + // Checks whether kernel idle timer should be active depending the policy decisions around + // refresh rates. + KernelIdleTimerAction getIdleTimerAction() const; + + bool supportsFrameRateOverrideByContent() const { return mSupportsFrameRateOverrideByContent; } + + // Return the display refresh rate divisor to match the layer + // frame rate, or 0 if the display refresh rate is not a multiple of the + // layer refresh rate. + static int getFrameRateDivisor(Fps displayRefreshRate, Fps layerFrameRate); + + // Returns if the provided frame rates have a ratio t*1000/1001 or t*1001/1000 + // for an integer t. + static bool isFractionalPairOrMultiple(Fps, Fps); + + using UidToFrameRateOverride = std::map; + + // Returns the frame rate override for each uid. + UidToFrameRateOverride getFrameRateOverrides(const std::vector&, + Fps displayFrameRate, GlobalSignals) const + EXCLUDES(mLock); + + std::optional kernelIdleTimerController() { + return mConfig.kernelIdleTimerController; + } + + struct IdleTimerCallbacks { + struct Callbacks { + std::function onReset; + std::function onExpired; + }; + + Callbacks platform; + Callbacks kernel; + }; + + void setIdleTimerCallbacks(IdleTimerCallbacks callbacks) EXCLUDES(mIdleTimerCallbacksMutex) { + std::scoped_lock lock(mIdleTimerCallbacksMutex); + mIdleTimerCallbacks = std::move(callbacks); + } + + void clearIdleTimerCallbacks() EXCLUDES(mIdleTimerCallbacksMutex) { + std::scoped_lock lock(mIdleTimerCallbacksMutex); + mIdleTimerCallbacks.reset(); + } + + void startIdleTimer() { + if (mIdleTimer) { + mIdleTimer->start(); + } + } + + void stopIdleTimer() { + if (mIdleTimer) { + mIdleTimer->stop(); + } + } + + void resetIdleTimer(bool kernelOnly) { + if (!mIdleTimer) { + return; + } + if (kernelOnly && !mConfig.kernelIdleTimerController.has_value()) { + return; + } + mIdleTimer->reset(); + } + + void dump(utils::Dumper&) const EXCLUDES(mLock); + + std::chrono::milliseconds getIdleTimerTimeout(); + +private: + friend struct TestableRefreshRateSelector; + + void constructAvailableRefreshRates() REQUIRES(mLock); + + // See mActiveModeIt for thread safety. + DisplayModeIterator getActiveModeItLocked() const REQUIRES(mLock); + + RankedRefreshRates getRankedRefreshRatesLocked(const std::vector&, + GlobalSignals) const REQUIRES(mLock); + + // Returns number of display frames and remainder when dividing the layer refresh period by + // display refresh period. + std::pair getDisplayFrames(nsecs_t layerPeriod, nsecs_t displayPeriod) const; + + // Returns the lowest refresh rate according to the current policy. May change at runtime. Only + // uses the primary range, not the app request range. + const DisplayModePtr& getMinRefreshRateByPolicyLocked() const REQUIRES(mLock); + + // Returns the highest refresh rate according to the current policy. May change at runtime. Only + // uses the primary range, not the app request range. + const DisplayModePtr& getMaxRefreshRateByPolicyLocked(int anchorGroup) const REQUIRES(mLock); + + struct RefreshRateScoreComparator; + + enum class RefreshRateOrder { Ascending, Descending }; + + // Only uses the primary range, not the app request range. + RefreshRateRanking rankRefreshRates(std::optional anchorGroupOpt, RefreshRateOrder, + std::optional preferredDisplayModeOpt = + std::nullopt) const REQUIRES(mLock); + + const Policy* getCurrentPolicyLocked() const REQUIRES(mLock); + bool isPolicyValidLocked(const Policy& policy) const REQUIRES(mLock); + + // Returns the refresh rate score as a ratio to max refresh rate, which has a score of 1. + float calculateRefreshRateScoreForFps(Fps refreshRate) const REQUIRES(mLock); + // calculates a score for a layer. Used to determine the display refresh rate + // and the frame rate override for certains applications. + float calculateLayerScoreLocked(const LayerRequirement&, Fps refreshRate, + bool isSeamlessSwitch) const REQUIRES(mLock); + + float calculateNonExactMatchingLayerScoreLocked(const LayerRequirement&, Fps refreshRate) const + REQUIRES(mLock); + + void updateDisplayModes(DisplayModes, DisplayModeId activeModeId) EXCLUDES(mLock) + REQUIRES(kMainThreadContext); + + void initializeIdleTimer(); + + std::optional getIdleTimerCallbacks() const + REQUIRES(mIdleTimerCallbacksMutex) { + if (!mIdleTimerCallbacks) return {}; + return mConfig.kernelIdleTimerController.has_value() ? mIdleTimerCallbacks->kernel + : mIdleTimerCallbacks->platform; + } + + // The display modes of the active display. The DisplayModeIterators below are pointers into + // this container, so must be invalidated whenever the DisplayModes change. The Policy below + // is also dependent, so must be reset as well. + DisplayModes mDisplayModes GUARDED_BY(mLock); + + // Written under mLock exclusively from kMainThreadContext, so reads from kMainThreadContext + // need not be under mLock. + DisplayModeIterator mActiveModeIt GUARDED_BY(mLock) GUARDED_BY(kMainThreadContext); + + DisplayModeIterator mMinRefreshRateModeIt GUARDED_BY(mLock); + DisplayModeIterator mMaxRefreshRateModeIt GUARDED_BY(mLock); + + // Display modes that satisfy the Policy's ranges, filtered and sorted by refresh rate. + std::vector mPrimaryRefreshRates GUARDED_BY(mLock); + std::vector mAppRequestRefreshRates GUARDED_BY(mLock); + + Policy mDisplayManagerPolicy GUARDED_BY(mLock); + std::optional mOverridePolicy GUARDED_BY(mLock); + + unsigned mNumModeSwitchesInPolicy GUARDED_BY(kMainThreadContext) = 0; + + mutable std::mutex mLock; + + // A sorted list of known frame rates that a Heuristic layer will choose + // from based on the closest value. + const std::vector mKnownFrameRates; + + const Config mConfig; + bool mSupportsFrameRateOverrideByContent; + + struct GetRankedRefreshRatesCache { + std::pair, GlobalSignals> arguments; + RankedRefreshRates result; + }; + mutable std::optional mGetRankedRefreshRatesCache GUARDED_BY(mLock); + + // Declare mIdleTimer last to ensure its thread joins before the mutex/callbacks are destroyed. + std::mutex mIdleTimerCallbacksMutex; + std::optional mIdleTimerCallbacks GUARDED_BY(mIdleTimerCallbacksMutex); + // Used to detect (lack of) frame activity. + std::optional mIdleTimer; +}; + +} // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index be3ebb7947..499cee68f1 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -68,8 +68,8 @@ Scheduler::~Scheduler() { mDisplayPowerTimer.reset(); mTouchTimer.reset(); - // Stop idle timer and clear callbacks, as the RefreshRateConfigs may outlive the Scheduler. - setRefreshRateConfigs(nullptr); + // Stop idle timer and clear callbacks, as the RefreshRateSelector may outlive the Scheduler. + setRefreshRateSelector(nullptr); } void Scheduler::startTimers() { @@ -94,17 +94,17 @@ void Scheduler::startTimers() { } } -void Scheduler::setRefreshRateConfigs(std::shared_ptr configs) { - // The current RefreshRateConfigs instance may outlive this call, so unbind its idle timer. +void Scheduler::setRefreshRateSelector(std::shared_ptr selectorPtr) { + // The current RefreshRateSelector instance may outlive this call, so unbind its idle timer. { - // mRefreshRateConfigsLock is not locked here to avoid the deadlock + // mRefreshRateSelectorLock is not locked here to avoid the deadlock // as the callback can attempt to acquire the lock before stopIdleTimer can finish // the execution. It's safe to FakeGuard as main thread is the only thread that - // writes to the mRefreshRateConfigs. - ftl::FakeGuard guard(mRefreshRateConfigsLock); - if (mRefreshRateConfigs) { - mRefreshRateConfigs->stopIdleTimer(); - mRefreshRateConfigs->clearIdleTimerCallbacks(); + // writes to the mRefreshRateSelector. + ftl::FakeGuard guard(mRefreshRateSelectorLock); + if (mRefreshRateSelector) { + mRefreshRateSelector->stopIdleTimer(); + mRefreshRateSelector->clearIdleTimerCallbacks(); } } { @@ -113,17 +113,17 @@ void Scheduler::setRefreshRateConfigs(std::shared_ptr config mPolicy = {}; } - std::scoped_lock lock(mRefreshRateConfigsLock); - mRefreshRateConfigs = std::move(configs); - if (!mRefreshRateConfigs) return; + std::scoped_lock lock(mRefreshRateSelectorLock); + mRefreshRateSelector = std::move(selectorPtr); + if (!mRefreshRateSelector) return; - mRefreshRateConfigs->setIdleTimerCallbacks( + mRefreshRateSelector->setIdleTimerCallbacks( {.platform = {.onReset = [this] { idleTimerCallback(TimerState::Reset); }, .onExpired = [this] { idleTimerCallback(TimerState::Expired); }}, .kernel = {.onReset = [this] { kernelIdleTimerCallback(TimerState::Reset); }, .onExpired = [this] { kernelIdleTimerCallback(TimerState::Expired); }}}); - mRefreshRateConfigs->startIdleTimer(); + mRefreshRateSelector->startIdleTimer(); } void Scheduler::registerDisplay(sp display) { @@ -174,9 +174,8 @@ std::unique_ptr Scheduler::makePrimaryDispSyncSource( } std::optional Scheduler::getFrameRateOverride(uid_t uid) const { - const auto refreshRateConfigs = holdRefreshRateConfigs(); const bool supportsFrameRateOverrideByContent = - refreshRateConfigs->supportsFrameRateOverrideByContent(); + holdRefreshRateSelector()->supportsFrameRateOverrideByContent(); return mFrameRateOverrideMappings .getFrameRateOverrideForUid(uid, supportsFrameRateOverrideByContent); } @@ -191,7 +190,7 @@ bool Scheduler::isVsyncValid(TimePoint expectedVsyncTimestamp, uid_t uid) const } impl::EventThread::ThrottleVsyncCallback Scheduler::makeThrottleVsyncCallback() const { - std::scoped_lock lock(mRefreshRateConfigsLock); + std::scoped_lock lock(mRefreshRateSelectorLock); return [this](nsecs_t expectedVsyncTimestamp, uid_t uid) { return !isVsyncValid(TimePoint::fromNs(expectedVsyncTimestamp), uid); @@ -200,7 +199,7 @@ impl::EventThread::ThrottleVsyncCallback Scheduler::makeThrottleVsyncCallback() impl::EventThread::GetVsyncPeriodFunction Scheduler::makeGetVsyncPeriodFunction() const { return [this](uid_t uid) { - const Fps refreshRate = holdRefreshRateConfigs()->getActiveModePtr()->getFps(); + const Fps refreshRate = holdRefreshRateSelector()->getActiveModePtr()->getFps(); const nsecs_t currentPeriod = mVsyncSchedule->period().ns() ?: refreshRate.getPeriodNsecs(); const auto frameRate = getFrameRateOverride(uid); @@ -208,7 +207,7 @@ impl::EventThread::GetVsyncPeriodFunction Scheduler::makeGetVsyncPeriodFunction( return currentPeriod; } - const auto divisor = RefreshRateConfigs::getFrameRateDivisor(refreshRate, *frameRate); + const auto divisor = RefreshRateSelector::getFrameRateDivisor(refreshRate, *frameRate); if (divisor <= 1) { return currentPeriod; } @@ -293,9 +292,8 @@ void Scheduler::onScreenReleased(ConnectionHandle handle) { } void Scheduler::onFrameRateOverridesChanged(ConnectionHandle handle, PhysicalDisplayId displayId) { - const auto refreshRateConfigs = holdRefreshRateConfigs(); const bool supportsFrameRateOverrideByContent = - refreshRateConfigs->supportsFrameRateOverrideByContent(); + holdRefreshRateSelector()->supportsFrameRateOverrideByContent(); std::vector overrides = mFrameRateOverrideMappings.getAllFrameRateOverrides(supportsFrameRateOverrideByContent); @@ -336,8 +334,8 @@ void Scheduler::dispatchCachedReportedMode() { // If the mode is not the current mode, this means that a // mode change is in progress. In that case we shouldn't dispatch an event // as it will be dispatched when the current mode changes. - if (std::scoped_lock lock(mRefreshRateConfigsLock); - mRefreshRateConfigs->getActiveModePtr() != mPolicy.mode) { + if (std::scoped_lock lock(mRefreshRateSelectorLock); + mRefreshRateSelector->getActiveModePtr() != mPolicy.mode) { return; } @@ -431,8 +429,8 @@ void Scheduler::resync() { if (now - last > kIgnoreDelay) { const auto refreshRate = [&] { - std::scoped_lock lock(mRefreshRateConfigsLock); - return mRefreshRateConfigs->getActiveModePtr()->getFps(); + std::scoped_lock lock(mRefreshRateSelectorLock); + return mRefreshRateSelector->getActiveModePtr()->getFps(); }(); resyncToHardwareVsync(false, refreshRate); } @@ -493,8 +491,8 @@ void Scheduler::deregisterLayer(Layer* layer) { void Scheduler::recordLayerHistory(Layer* layer, nsecs_t presentTime, LayerHistory::LayerUpdateType updateType) { { - std::scoped_lock lock(mRefreshRateConfigsLock); - if (!mRefreshRateConfigs->canSwitch()) return; + std::scoped_lock lock(mRefreshRateSelectorLock); + if (!mRefreshRateSelector->canSwitch()) return; } mLayerHistory.record(layer, presentTime, systemTime(), updateType); @@ -510,26 +508,26 @@ void Scheduler::setDefaultFrameRateCompatibility(Layer* layer) { } void Scheduler::chooseRefreshRateForContent() { - const auto configs = holdRefreshRateConfigs(); - if (!configs->canSwitch()) return; + const auto selectorPtr = holdRefreshRateSelector(); + if (!selectorPtr->canSwitch()) return; ATRACE_CALL(); - LayerHistory::Summary summary = mLayerHistory.summarize(*configs, systemTime()); + LayerHistory::Summary summary = mLayerHistory.summarize(*selectorPtr, systemTime()); applyPolicy(&Policy::contentRequirements, std::move(summary)); } void Scheduler::resetIdleTimer() { - std::scoped_lock lock(mRefreshRateConfigsLock); - mRefreshRateConfigs->resetIdleTimer(/*kernelOnly*/ false); + std::scoped_lock lock(mRefreshRateSelectorLock); + mRefreshRateSelector->resetIdleTimer(/*kernelOnly*/ false); } void Scheduler::onTouchHint() { if (mTouchTimer) { mTouchTimer->reset(); - std::scoped_lock lock(mRefreshRateConfigsLock); - mRefreshRateConfigs->resetIdleTimer(/*kernelOnly*/ true); + std::scoped_lock lock(mRefreshRateSelectorLock); + mRefreshRateSelector->resetIdleTimer(/*kernelOnly*/ true); } } @@ -555,8 +553,8 @@ void Scheduler::kernelIdleTimerCallback(TimerState state) { // TODO(145561154): cleanup the kernel idle timer implementation and the refresh rate // magic number const Fps refreshRate = [&] { - std::scoped_lock lock(mRefreshRateConfigsLock); - return mRefreshRateConfigs->getActiveModePtr()->getFps(); + std::scoped_lock lock(mRefreshRateSelectorLock); + return mRefreshRateSelector->getActiveModePtr()->getFps(); }(); constexpr Fps FPS_THRESHOLD_FOR_KERNEL_TIMER = 65_Hz; @@ -623,15 +621,14 @@ void Scheduler::dumpVsync(std::string& out) const { } bool Scheduler::updateFrameRateOverrides(GlobalSignals consideredSignals, Fps displayRefreshRate) { - const auto refreshRateConfigs = holdRefreshRateConfigs(); - // we always update mFrameRateOverridesByContent here // supportsFrameRateOverridesByContent will be checked // when getting FrameRateOverrides from mFrameRateOverrideMappings if (!consideredSignals.idle) { const auto frameRateOverrides = - refreshRateConfigs->getFrameRateOverrides(mPolicy.contentRequirements, - displayRefreshRate, consideredSignals); + holdRefreshRateSelector()->getFrameRateOverrides(mPolicy.contentRequirements, + displayRefreshRate, + consideredSignals); return mFrameRateOverrideMappings.updateFrameRateOverridesByContent(frameRateOverrides); } return false; @@ -645,7 +642,6 @@ auto Scheduler::applyPolicy(S Policy::*statePtr, T&& newState) -> GlobalSignals bool refreshRateChanged = false; bool frameRateOverridesChanged; - const auto refreshRateConfigs = holdRefreshRateConfigs(); { std::lock_guard lock(mPolicyLock); @@ -698,7 +694,7 @@ auto Scheduler::applyPolicy(S Policy::*statePtr, T&& newState) -> GlobalSignals auto Scheduler::chooseDisplayModes() const -> DisplayModeChoiceMap { ATRACE_CALL(); - using RankedRefreshRates = RefreshRateConfigs::RankedRefreshRates; + using RankedRefreshRates = RefreshRateSelector::RankedRefreshRates; display::PhysicalDisplayVector perDisplayRanking; // Tallies the score of a refresh rate across `displayCount` displays. @@ -717,7 +713,7 @@ auto Scheduler::chooseDisplayModes() const -> DisplayModeChoiceMap { for (const auto& [id, display] : mDisplays) { auto rankedRefreshRates = - display->holdRefreshRateConfigs() + display->holdRefreshRateSelector() ->getRankedRefreshRates(mPolicy.contentRequirements, globalSignals); for (const auto& [modePtr, score] : rankedRefreshRates.ranking) { @@ -793,9 +789,9 @@ DisplayModePtr Scheduler::getPreferredDisplayMode() { std::lock_guard lock(mPolicyLock); // Make sure the stored mode is up to date. if (mPolicy.mode) { - const auto configs = holdRefreshRateConfigs(); const auto ranking = - configs->getRankedRefreshRates(mPolicy.contentRequirements, makeGlobalSignals()) + holdRefreshRateSelector() + ->getRankedRefreshRates(mPolicy.contentRequirements, makeGlobalSignals()) .ranking; mPolicy.mode = ranking.front().modePtr; diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 33f612632b..39c41b99da 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -45,7 +45,7 @@ #include "LayerHistory.h" #include "MessageQueue.h" #include "OneShotTimer.h" -#include "RefreshRateConfigs.h" +#include "RefreshRateSelector.h" #include "VsyncSchedule.h" namespace android::scheduler { @@ -87,7 +87,7 @@ class TokenManager; namespace scheduler { -using GlobalSignals = RefreshRateConfigs::GlobalSignals; +using GlobalSignals = RefreshRateSelector::GlobalSignals; struct ISchedulerCallback { virtual void setVsyncEnabled(bool) = 0; @@ -107,8 +107,8 @@ public: virtual ~Scheduler(); void startTimers(); - void setRefreshRateConfigs(std::shared_ptr) - EXCLUDES(mRefreshRateConfigsLock); + void setRefreshRateSelector(std::shared_ptr) + EXCLUDES(mRefreshRateSelectorLock); void registerDisplay(sp); void unregisterDisplay(PhysicalDisplayId); @@ -163,7 +163,7 @@ public: // Otherwise, if hardware vsync is not already enabled then this method will // no-op. void resyncToHardwareVsync(bool makeAvailable, Fps refreshRate); - void resync() EXCLUDES(mRefreshRateConfigsLock); + void resync() EXCLUDES(mRefreshRateSelectorLock); void forceNextResync() { mLastResyncTime = 0; } // Passes a vsync sample to VsyncController. periodFlushed will be true if @@ -175,13 +175,13 @@ public: // Layers are registered on creation, and unregistered when the weak reference expires. void registerLayer(Layer*); void recordLayerHistory(Layer*, nsecs_t presentTime, LayerHistory::LayerUpdateType updateType) - EXCLUDES(mRefreshRateConfigsLock); + EXCLUDES(mRefreshRateSelectorLock); void setModeChangePending(bool pending); void setDefaultFrameRateCompatibility(Layer*); void deregisterLayer(Layer*); // Detects content using layer history, and selects a matching refresh rate. - void chooseRefreshRateForContent() EXCLUDES(mRefreshRateConfigsLock); + void chooseRefreshRateForContent() EXCLUDES(mRefreshRateSelectorLock); void resetIdleTimer(); @@ -226,11 +226,11 @@ public: void setGameModeRefreshRateForUid(FrameRateOverride); // Retrieves the overridden refresh rate for a given uid. - std::optional getFrameRateOverride(uid_t uid) const EXCLUDES(mRefreshRateConfigsLock); + std::optional getFrameRateOverride(uid_t uid) const EXCLUDES(mRefreshRateSelectorLock); - nsecs_t getVsyncPeriodFromRefreshRateConfigs() const EXCLUDES(mRefreshRateConfigsLock) { - std::scoped_lock lock(mRefreshRateConfigsLock); - return mRefreshRateConfigs->getActiveModePtr()->getFps().getPeriodNsecs(); + nsecs_t getVsyncPeriodFromRefreshRateSelector() const EXCLUDES(mRefreshRateSelectorLock) { + std::scoped_lock lock(mRefreshRateSelectorLock); + return mRefreshRateSelector->getActiveModePtr()->getFps().getPeriodNsecs(); } // Returns the framerate of the layer with the given sequence ID @@ -254,7 +254,7 @@ private: EventThread*, EventRegistrationFlags eventRegistration = {}); // Update feature state machine to given state when corresponding timer resets or expires. - void kernelIdleTimerCallback(TimerState) EXCLUDES(mRefreshRateConfigsLock); + void kernelIdleTimerCallback(TimerState) EXCLUDES(mRefreshRateSelectorLock); void idleTimerCallback(TimerState); void touchTimerCallback(TimerState); void displayPowerTimerCallback(TimerState); @@ -293,16 +293,16 @@ private: bool updateFrameRateOverrides(GlobalSignals, Fps displayRefreshRate) REQUIRES(mPolicyLock); - void dispatchCachedReportedMode() REQUIRES(mPolicyLock) EXCLUDES(mRefreshRateConfigsLock); + void dispatchCachedReportedMode() REQUIRES(mPolicyLock) EXCLUDES(mRefreshRateSelectorLock); android::impl::EventThread::ThrottleVsyncCallback makeThrottleVsyncCallback() const - EXCLUDES(mRefreshRateConfigsLock); + EXCLUDES(mRefreshRateSelectorLock); android::impl::EventThread::GetVsyncPeriodFunction makeGetVsyncPeriodFunction() const; - std::shared_ptr holdRefreshRateConfigs() const - EXCLUDES(mRefreshRateConfigsLock) { - std::scoped_lock lock(mRefreshRateConfigsLock); - return mRefreshRateConfigs; + std::shared_ptr holdRefreshRateSelector() const + EXCLUDES(mRefreshRateSelectorLock) { + std::scoped_lock lock(mRefreshRateSelectorLock); + return mRefreshRateSelector; } // Stores EventThread associated with a given VSyncSource, and an initial EventThreadConnection. @@ -359,8 +359,8 @@ private: std::optional cachedModeChangedParams; } mPolicy GUARDED_BY(mPolicyLock); - mutable std::mutex mRefreshRateConfigsLock; - std::shared_ptr mRefreshRateConfigs GUARDED_BY(mRefreshRateConfigsLock); + mutable std::mutex mRefreshRateSelectorLock; + std::shared_ptr mRefreshRateSelector GUARDED_BY(mRefreshRateSelectorLock); std::mutex mVsyncTimelineLock; std::optional mLastVsyncPeriodChangeTimeline diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp index 898e86578a..0ad42364a2 100644 --- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp @@ -34,7 +34,7 @@ #include #include -#include "RefreshRateConfigs.h" +#include "RefreshRateSelector.h" #include "VSyncPredictor.h" namespace android::scheduler { @@ -274,7 +274,7 @@ bool VSyncPredictor::isVSyncInPhase(nsecs_t timePoint, Fps frameRate) const { std::lock_guard lock(mMutex); const auto divisor = - RefreshRateConfigs::getFrameRateDivisor(Fps::fromPeriodNsecs(mIdealPeriod), frameRate); + RefreshRateSelector::getFrameRateDivisor(Fps::fromPeriodNsecs(mIdealPeriod), frameRate); if (divisor <= 1 || timePoint == 0) { return true; } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index c1eda1793d..167115cd2d 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -184,7 +184,7 @@ using ui::Dataspace; using ui::DisplayPrimaries; using ui::RenderIntent; -using KernelIdleTimerController = scheduler::RefreshRateConfigs::KernelIdleTimerController; +using KernelIdleTimerController = scheduler::RefreshRateSelector::KernelIdleTimerController; namespace hal = android::hardware::graphics::composer::hal; @@ -1030,7 +1030,7 @@ status_t SurfaceFlinger::getDynamicDisplayInfo(const sp& displayToken, const PhysicalDisplayId displayId = snapshot.displayId(); - info->activeDisplayModeId = display->refreshRateConfigs().getActiveModePtr()->getId().value(); + info->activeDisplayModeId = display->refreshRateSelector().getActiveModePtr()->getId().value(); info->activeColorMode = display->getCompositionDisplay()->getState().colorMode; info->hdrCapabilities = display->getHdrCapabilities(); @@ -1127,11 +1127,11 @@ status_t SurfaceFlinger::setActiveModeFromBackdoor(const sprefreshRateConfigs().getCurrentPolicy().allowGroupSwitching; + display->refreshRateSelector().getCurrentPolicy().allowGroupSwitching; - const scheduler::RefreshRateConfigs::DisplayManagerPolicy policy{modeId, - allowGroupSwitching, - {fps, fps}}; + const scheduler::RefreshRateSelector::DisplayManagerPolicy policy{modeId, + allowGroupSwitching, + {fps, fps}}; return setDesiredDisplayModeSpecsInternal(display, policy); }); @@ -1249,7 +1249,7 @@ void SurfaceFlinger::setActiveModeInHwcIfNeeded() { // Desired active mode was set, it is different than the mode currently in use, however // allowed modes might have changed by the time we process the refresh. // Make sure the desired mode is still allowed - const auto displayModeAllowed = display->refreshRateConfigs().isModeAllowed(desiredModeId); + const auto displayModeAllowed = display->refreshRateSelector().isModeAllowed(desiredModeId); if (!displayModeAllowed) { clearDesiredActiveModeState(display); continue; @@ -1271,7 +1271,7 @@ void SurfaceFlinger::setActiveModeInHwcIfNeeded() { continue; } - display->refreshRateConfigs().onModeChangeInitiated(); + display->refreshRateSelector().onModeChangeInitiated(); mScheduler->onNewVsyncPeriodChangeTimeline(outTimeline); if (outTimeline.refreshRequired) { @@ -2771,21 +2771,21 @@ sp SurfaceFlinger::setupNewDisplayDeviceInternal( const auto [kernelIdleTimerController, idleTimerTimeoutMs] = getKernelIdleTimerProperties(compositionDisplay->getId()); - scheduler::RefreshRateConfigs::Config config = + scheduler::RefreshRateSelector::Config config = {.enableFrameRateOverride = android::sysprop::enable_frame_rate_override(false), .frameRateMultipleThreshold = base::GetIntProperty("debug.sf.frame_rate_multiple_threshold", 0), .idleTimerTimeout = idleTimerTimeoutMs, .kernelIdleTimerController = kernelIdleTimerController}; - creationArgs.refreshRateConfigs = + creationArgs.refreshRateSelector = mPhysicalDisplays.get(physical->id) .transform(&PhysicalDisplay::snapshotRef) .transform([&](const display::DisplaySnapshot& snapshot) { return std::make_shared< - scheduler::RefreshRateConfigs>(snapshot.displayModes(), - creationArgs.activeModeId, - config); + scheduler::RefreshRateSelector>(snapshot.displayModes(), + creationArgs.activeModeId, + config); }) .value_or(nullptr); @@ -2933,7 +2933,7 @@ void SurfaceFlinger::processDisplayAdded(const wp& displayToken, if (mScheduler && !display->isVirtual()) { // Display modes are reloaded on hotplug reconnect. if (display->isPrimary()) { - mScheduler->setRefreshRateConfigs(display->holdRefreshRateConfigs()); + mScheduler->setRefreshRateSelector(display->holdRefreshRateSelector()); } mScheduler->registerDisplay(display); dispatchDisplayHotplugEvent(display->getPhysicalId(), true); @@ -3349,7 +3349,7 @@ void SurfaceFlinger::requestDisplayModes(std::vectorrefreshRateConfigs().isModeAllowed(modePtr->getId())) { + if (display->refreshRateSelector().isModeAllowed(modePtr->getId())) { setDesiredActiveMode(std::move(request)); } else { ALOGV("%s: Mode %d is disallowed for display %s", __func__, modePtr->getId().value(), @@ -3370,7 +3370,7 @@ void SurfaceFlinger::triggerOnFrameRateOverridesChanged() { void SurfaceFlinger::initScheduler(const sp& display) { LOG_ALWAYS_FATAL_IF(mScheduler); - const auto activeModePtr = display->refreshRateConfigs().getActiveModePtr(); + const auto activeModePtr = display->refreshRateSelector().getActiveModePtr(); const Fps activeRefreshRate = activeModePtr->getFps(); mRefreshRateStats = std::make_unique(*mTimeStats, activeRefreshRate, @@ -3397,13 +3397,13 @@ void SurfaceFlinger::initScheduler(const sp& display) { static_cast(*this), features); { - auto configs = display->holdRefreshRateConfigs(); - if (configs->kernelIdleTimerController().has_value()) { + auto selectorPtr = display->holdRefreshRateSelector(); + if (selectorPtr->kernelIdleTimerController()) { features |= Feature::kKernelIdleTimer; } mScheduler->createVsyncSchedule(features); - mScheduler->setRefreshRateConfigs(std::move(configs)); + mScheduler->setRefreshRateSelector(std::move(selectorPtr)); mScheduler->registerDisplay(display); } setVsyncEnabled(false); @@ -4650,7 +4650,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp& display, hal: display->setPowerMode(mode); - const auto refreshRate = display->refreshRateConfigs().getActiveMode().getFps(); + const auto refreshRate = display->refreshRateSelector().getActiveMode().getFps(); if (*currentMode == hal::PowerMode::OFF) { // Turn on the display if (isInternalDisplay && (!activeDisplay || !activeDisplay->isPoweredOn())) { @@ -5189,7 +5189,7 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, const std::string& comp if (const auto display = getDefaultDisplayDeviceLocked()) { std::string fps, xDpi, yDpi; - if (const auto activeModePtr = display->refreshRateConfigs().getActiveModePtr()) { + if (const auto activeModePtr = display->refreshRateSelector().getActiveModePtr()) { fps = to_string(activeModePtr->getFps()); const auto dpi = activeModePtr->getDpi(); @@ -5735,8 +5735,8 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r // defaultMode. The defaultMode doesn't matter for the override // policy though, since we set allowGroupSwitching to true, so it's // not a problem. - scheduler::RefreshRateConfigs::OverridePolicy overridePolicy; - overridePolicy.defaultMode = display->refreshRateConfigs() + scheduler::RefreshRateSelector::OverridePolicy overridePolicy; + overridePolicy.defaultMode = display->refreshRateSelector() .getDisplayManagerPolicy() .defaultMode; overridePolicy.allowGroupSwitching = true; @@ -5749,7 +5749,8 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()); return setDesiredDisplayModeSpecsInternal( - display, scheduler::RefreshRateConfigs::NoOverridePolicy{}); + display, + scheduler::RefreshRateSelector::NoOverridePolicy{}); }) .get(); } @@ -5860,7 +5861,7 @@ void SurfaceFlinger::kernelTimerChanged(bool expired) { if (!updateOverlay) return; // Update the overlay on the main thread to avoid race conditions with - // mRefreshRateConfigs->getActiveMode() + // RefreshRateSelector::getActiveMode. static_cast(mScheduler->schedule([=] { const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()); if (!display) { @@ -5924,7 +5925,7 @@ void SurfaceFlinger::updateKernelIdleTimer(std::chrono::milliseconds timeout, } void SurfaceFlinger::toggleKernelIdleTimer() { - using KernelIdleTimerAction = scheduler::RefreshRateConfigs::KernelIdleTimerAction; + using KernelIdleTimerAction = scheduler::RefreshRateSelector::KernelIdleTimerAction; const auto display = getDefaultDisplayDeviceLocked(); if (!display) { @@ -5935,12 +5936,12 @@ void SurfaceFlinger::toggleKernelIdleTimer() { // If the support for kernel idle timer is disabled for the active display, // don't do anything. const std::optional kernelIdleTimerController = - display->refreshRateConfigs().kernelIdleTimerController(); + display->refreshRateSelector().kernelIdleTimerController(); if (!kernelIdleTimerController.has_value()) { return; } - const KernelIdleTimerAction action = display->refreshRateConfigs().getIdleTimerAction(); + const KernelIdleTimerAction action = display->refreshRateSelector().getIdleTimerAction(); switch (action) { case KernelIdleTimerAction::TurnOff: @@ -5956,7 +5957,7 @@ void SurfaceFlinger::toggleKernelIdleTimer() { if (!mKernelIdleTimerEnabled) { ATRACE_INT("KernelIdleTimer", 1); const std::chrono::milliseconds timeout = - display->refreshRateConfigs().getIdleTimerTimeout(); + display->refreshRateSelector().getIdleTimerTimeout(); updateKernelIdleTimer(timeout, kernelIdleTimerController.value(), display->getPhysicalId()); mKernelIdleTimerEnabled = true; @@ -6598,7 +6599,7 @@ std::optional> SurfaceFlinger::getPreferredDisplayM status_t SurfaceFlinger::setDesiredDisplayModeSpecsInternal( const sp& display, - const scheduler::RefreshRateConfigs::PolicyVariant& policy) { + const scheduler::RefreshRateSelector::PolicyVariant& policy) { const auto displayId = display->getPhysicalId(); Mutex::Autolock lock(mStateLock); @@ -6608,10 +6609,10 @@ status_t SurfaceFlinger::setDesiredDisplayModeSpecsInternal( return NO_ERROR; } - auto& configs = display->refreshRateConfigs(); - using SetPolicyResult = scheduler::RefreshRateConfigs::SetPolicyResult; + auto& selector = display->refreshRateSelector(); + using SetPolicyResult = scheduler::RefreshRateSelector::SetPolicyResult; - switch (configs.setPolicy(policy)) { + switch (selector.setPolicy(policy)) { case SetPolicyResult::Invalid: return BAD_VALUE; case SetPolicyResult::Unchanged: @@ -6620,12 +6621,12 @@ status_t SurfaceFlinger::setDesiredDisplayModeSpecsInternal( break; } - const scheduler::RefreshRateConfigs::Policy currentPolicy = configs.getCurrentPolicy(); + const scheduler::RefreshRateSelector::Policy currentPolicy = selector.getCurrentPolicy(); ALOGV("Setting desired display mode specs: %s", currentPolicy.toString().c_str()); // TODO(b/140204874): Leave the event in until we do proper testing with all apps that might // be depending in this callback. - if (const auto activeModePtr = configs.getActiveModePtr(); displayId == mActiveDisplayId) { + if (const auto activeModePtr = selector.getActiveModePtr(); displayId == mActiveDisplayId) { mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, activeModePtr); toggleKernelIdleTimer(); } else { @@ -6644,7 +6645,7 @@ status_t SurfaceFlinger::setDesiredDisplayModeSpecsInternal( ALOGV("Switching to Scheduler preferred mode %d (%s)", preferredModeId.value(), to_string(preferredMode->getFps()).c_str()); - if (!configs.isModeAllowed(preferredModeId)) { + if (!selector.isModeAllowed(preferredModeId)) { ALOGE("%s: Preferred mode %d is disallowed", __func__, preferredModeId.value()); return INVALID_OPERATION; } @@ -6673,7 +6674,7 @@ status_t SurfaceFlinger::setDesiredDisplayModeSpecs( ALOGW("Attempt to set desired display modes for virtual display"); return INVALID_OPERATION; } else { - using Policy = scheduler::RefreshRateConfigs::DisplayManagerPolicy; + using Policy = scheduler::RefreshRateSelector::DisplayManagerPolicy; const Policy policy{DisplayModeId(defaultMode), allowGroupSwitching, {Fps::fromValue(primaryRefreshRateMin), @@ -6712,8 +6713,8 @@ status_t SurfaceFlinger::getDesiredDisplayModeSpecs(const sp& displayTo return INVALID_OPERATION; } - scheduler::RefreshRateConfigs::Policy policy = - display->refreshRateConfigs().getDisplayManagerPolicy(); + scheduler::RefreshRateSelector::Policy policy = + display->refreshRateSelector().getDisplayManagerPolicy(); *outDefaultMode = policy.defaultMode.value(); *outAllowGroupSwitching = policy.allowGroupSwitching; *outPrimaryRefreshRateMin = policy.primaryRange.min.getValue(); @@ -6834,7 +6835,7 @@ status_t SurfaceFlinger::getMaxAcquiredBufferCount(int* buffers) const { if (!getHwComposer().isHeadless()) { if (const auto display = getDefaultDisplayDevice()) { - maxRefreshRate = display->refreshRateConfigs().getSupportedRefreshRateRange().max; + maxRefreshRate = display->refreshRateSelector().getSupportedRefreshRateRange().max; } } @@ -6849,7 +6850,7 @@ uint32_t SurfaceFlinger::getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t ui refreshRate = *frameRateOverride; } else if (!getHwComposer().isHeadless()) { if (const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked())) { - refreshRate = display->refreshRateConfigs().getActiveModePtr()->getFps(); + refreshRate = display->refreshRateSelector().getActiveModePtr()->getFps(); } } @@ -6938,7 +6939,7 @@ void SurfaceFlinger::onActiveDisplayChangedLocked(const sp& activ activeDisplay->getCompositionDisplay()->setLayerCachingTexturePoolEnabled(true); updateInternalDisplayVsyncLocked(activeDisplay); mScheduler->setModeChangePending(false); - mScheduler->setRefreshRateConfigs(activeDisplay->holdRefreshRateConfigs()); + mScheduler->setRefreshRateSelector(activeDisplay->holdRefreshRateSelector()); onActiveDisplaySizeChanged(activeDisplay); mActiveDisplayTransformHint = activeDisplay->getTransformHint(); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 9ffe6abbe6..d5b3a0737b 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -69,7 +69,7 @@ #include "FrontEnd/LayerCreationArgs.h" #include "FrontEnd/TransactionHandler.h" #include "LayerVector.h" -#include "Scheduler/RefreshRateConfigs.h" +#include "Scheduler/RefreshRateSelector.h" #include "Scheduler/RefreshRateStats.h" #include "Scheduler/Scheduler.h" #include "Scheduler/VsyncModulator.h" @@ -465,7 +465,7 @@ private: typename Handler = VsyncModulator::VsyncConfigOpt (VsyncModulator::*)(Args...)> void modulateVsync(Handler handler, Args... args) { if (const auto config = (*mVsyncModulator.*handler)(args...)) { - const auto vsyncPeriod = mScheduler->getVsyncPeriodFromRefreshRateConfigs(); + const auto vsyncPeriod = mScheduler->getVsyncPeriodFromRefreshRateSelector(); setVsyncConfig(*config, vsyncPeriod); } } @@ -634,7 +634,7 @@ private: // Toggles the kernel idle timer on or off depending the policy decisions around refresh rates. void toggleKernelIdleTimer() REQUIRES(mStateLock); - using KernelIdleTimerController = scheduler::RefreshRateConfigs::KernelIdleTimerController; + using KernelIdleTimerController = scheduler::RefreshRateSelector::KernelIdleTimerController; // Get the controller and timeout that will help decide how the kernel idle timer will be // configured and what value to use as the timeout. @@ -673,8 +673,8 @@ private: std::optional> getPreferredDisplayMode( PhysicalDisplayId, DisplayModeId defaultModeId) const REQUIRES(mStateLock); - status_t setDesiredDisplayModeSpecsInternal(const sp&, - const scheduler::RefreshRateConfigs::PolicyVariant&) + status_t setDesiredDisplayModeSpecsInternal( + const sp&, const scheduler::RefreshRateSelector::PolicyVariant&) EXCLUDES(mStateLock) REQUIRES(kMainThreadContext); void commitTransactions() EXCLUDES(mStateLock) REQUIRES(kMainThreadContext); diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h index 41edd22102..f310c4ac53 100644 --- a/services/surfaceflinger/SurfaceFlingerFactory.h +++ b/services/surfaceflinger/SurfaceFlingerFactory.h @@ -52,7 +52,6 @@ class CompositionEngine; namespace scheduler { class VsyncConfiguration; class VsyncController; -class RefreshRateConfigs; } // namespace scheduler namespace frametimeline { diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h index 99279dce8b..cf2b29012d 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h +++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h @@ -38,7 +38,7 @@ #include "NativeWindowSurface.h" #include "Scheduler/EventThread.h" #include "Scheduler/MessageQueue.h" -#include "Scheduler/RefreshRateConfigs.h" +#include "Scheduler/RefreshRateSelector.h" #include "Scheduler/VSyncTracker.h" #include "Scheduler/VsyncConfiguration.h" #include "Scheduler/VsyncController.h" @@ -217,18 +217,19 @@ namespace scheduler { class TestableScheduler : public Scheduler, private ICompositor { public: - TestableScheduler(const std::shared_ptr &refreshRateConfigs, - ISchedulerCallback &callback) + TestableScheduler(const std::shared_ptr& selectorPtr, + ISchedulerCallback& callback) : TestableScheduler(std::make_unique(), - std::make_unique(), refreshRateConfigs, + std::make_unique(), selectorPtr, callback) {} TestableScheduler(std::unique_ptr controller, std::unique_ptr tracker, - std::shared_ptr configs, ISchedulerCallback &callback) + std::shared_ptr selectorPtr, + ISchedulerCallback& callback) : Scheduler(*this, callback, Feature::kContentDetection) { mVsyncSchedule.emplace(VsyncSchedule(std::move(tracker), nullptr, std::move(controller))); - setRefreshRateConfigs(std::move(configs)); + setRefreshRateSelector(std::move(selectorPtr)); } ConnectionHandle createConnection(std::unique_ptr eventThread) { @@ -240,7 +241,7 @@ public: auto &mutableLayerHistory() { return mLayerHistory; } - auto refreshRateConfigs() { return holdRefreshRateConfigs(); } + auto refreshRateSelector() { return holdRefreshRateSelector(); } void replaceTouchTimer(int64_t millis) { if (mTouchTimer) { @@ -309,8 +310,8 @@ public: } std::unique_ptr createScheduler( - const std::shared_ptr &, - scheduler::ISchedulerCallback &) { + const std::shared_ptr&, + scheduler::ISchedulerCallback&) { return nullptr; } @@ -659,9 +660,9 @@ public: modes.try_emplace(kModeId90, mock::createDisplayMode(kModeId90, 90_Hz)); } - mRefreshRateConfigs = std::make_shared(modes, kModeId60); + mRefreshRateSelector = std::make_shared(modes, kModeId60); const auto fps = - FTL_FAKE_GUARD(kMainThreadContext, mRefreshRateConfigs->getActiveMode().getFps()); + FTL_FAKE_GUARD(kMainThreadContext, mRefreshRateSelector->getActiveMode().getFps()); mFlinger->mVsyncConfiguration = mFactory.createVsyncConfiguration(fps); mFlinger->mVsyncModulator = sp::make( mFlinger->mVsyncConfiguration->getCurrentConfigs()); @@ -670,7 +671,7 @@ public: hal::PowerMode::OFF); mScheduler = new scheduler::TestableScheduler(std::move(vsyncController), - std::move(vsyncTracker), mRefreshRateConfigs, + std::move(vsyncTracker), mRefreshRateSelector, *(callback ?: this)); mFlinger->mAppConnectionHandle = mScheduler->createConnection(std::move(appEventThread)); @@ -788,7 +789,7 @@ private: sp mFlinger = sp::make(mFactory, SurfaceFlinger::SkipInitialization); scheduler::TestableScheduler *mScheduler = nullptr; - std::shared_ptr mRefreshRateConfigs; + std::shared_ptr mRefreshRateSelector; }; } // namespace android diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp index 2614288016..f2d008d59f 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp +++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp @@ -23,6 +23,7 @@ #include "Scheduler/DispSyncSource.h" #include "Scheduler/OneShotTimer.h" +#include "Scheduler/RefreshRateSelector.h" #include "Scheduler/VSyncDispatchTimerQueue.h" #include "Scheduler/VSyncPredictor.h" #include "Scheduler/VSyncReactor.h" @@ -38,7 +39,7 @@ constexpr nsecs_t kVsyncPeriods[] = {(30_Hz).getPeriodNsecs(), (60_Hz).getPeriod (72_Hz).getPeriodNsecs(), (90_Hz).getPeriodNsecs(), (120_Hz).getPeriodNsecs()}; -constexpr auto kLayerVoteTypes = ftl::enum_range(); +constexpr auto kLayerVoteTypes = ftl::enum_range(); constexpr PowerMode kPowerModes[] = {PowerMode::ON, PowerMode::DOZE, PowerMode::OFF, PowerMode::DOZE_SUSPEND, PowerMode::ON_SUSPEND}; @@ -59,7 +60,7 @@ public: private: void fuzzRefreshRateSelection(); - void fuzzRefreshRateConfigs(); + void fuzzRefreshRateSelector(); void fuzzPresentLatencyTracker(); void fuzzVSyncModulator(); void fuzzVSyncPredictor(); @@ -238,8 +239,8 @@ void SchedulerFuzzer::fuzzLayerHistory() { time1 += mFdp.PickValueInArray(kVsyncPeriods); time2 += mFdp.PickValueInArray(kVsyncPeriods); } - historyV1.summarize(*scheduler->refreshRateConfigs(), time1); - historyV1.summarize(*scheduler->refreshRateConfigs(), time2); + historyV1.summarize(*scheduler->refreshRateSelector(), time1); + historyV1.summarize(*scheduler->refreshRateSelector(), time2); scheduler->createConnection(std::make_unique()); @@ -327,9 +328,9 @@ void SchedulerFuzzer::fuzzRefreshRateSelection() { layer->setFrameRateSelectionPriority(mFdp.ConsumeIntegral()); } -void SchedulerFuzzer::fuzzRefreshRateConfigs() { - using RefreshRateConfigs = scheduler::RefreshRateConfigs; - using LayerRequirement = RefreshRateConfigs::LayerRequirement; +void SchedulerFuzzer::fuzzRefreshRateSelector() { + using RefreshRateSelector = scheduler::RefreshRateSelector; + using LayerRequirement = RefreshRateSelector::LayerRequirement; using RefreshRateStats = scheduler::RefreshRateStats; const uint16_t minRefreshRate = mFdp.ConsumeIntegralInRange(1, UINT16_MAX >> 1); @@ -345,48 +346,48 @@ void SchedulerFuzzer::fuzzRefreshRateConfigs() { Fps::fromValue(static_cast(fps)))); } - RefreshRateConfigs refreshRateConfigs(displayModes, modeId); + RefreshRateSelector refreshRateSelector(displayModes, modeId); - const RefreshRateConfigs::GlobalSignals globalSignals = {.touch = false, .idle = false}; + const RefreshRateSelector::GlobalSignals globalSignals = {.touch = false, .idle = false}; std::vector layers = {{.weight = mFdp.ConsumeFloatingPoint()}}; - refreshRateConfigs.getRankedRefreshRates(layers, globalSignals); + refreshRateSelector.getRankedRefreshRates(layers, globalSignals); layers[0].name = mFdp.ConsumeRandomLengthString(kRandomStringLength); layers[0].ownerUid = mFdp.ConsumeIntegral(); layers[0].desiredRefreshRate = Fps::fromValue(mFdp.ConsumeFloatingPoint()); layers[0].vote = mFdp.PickValueInArray(kLayerVoteTypes.values); auto frameRateOverrides = - refreshRateConfigs.getFrameRateOverrides(layers, - Fps::fromValue( - mFdp.ConsumeFloatingPoint()), - globalSignals); + refreshRateSelector.getFrameRateOverrides(layers, + Fps::fromValue( + mFdp.ConsumeFloatingPoint()), + globalSignals); { ftl::FakeGuard guard(kMainThreadContext); - refreshRateConfigs.setPolicy( - RefreshRateConfigs:: + refreshRateSelector.setPolicy( + RefreshRateSelector:: DisplayManagerPolicy{modeId, {Fps::fromValue(mFdp.ConsumeFloatingPoint()), Fps::fromValue(mFdp.ConsumeFloatingPoint())}}); - refreshRateConfigs.setPolicy( - RefreshRateConfigs::OverridePolicy{modeId, - {Fps::fromValue( - mFdp.ConsumeFloatingPoint()), - Fps::fromValue( - mFdp.ConsumeFloatingPoint())}}); - refreshRateConfigs.setPolicy(RefreshRateConfigs::NoOverridePolicy{}); + refreshRateSelector.setPolicy( + RefreshRateSelector::OverridePolicy{modeId, + {Fps::fromValue( + mFdp.ConsumeFloatingPoint()), + Fps::fromValue( + mFdp.ConsumeFloatingPoint())}}); + refreshRateSelector.setPolicy(RefreshRateSelector::NoOverridePolicy{}); - refreshRateConfigs.setActiveModeId(modeId); + refreshRateSelector.setActiveModeId(modeId); } - RefreshRateConfigs::isFractionalPairOrMultiple(Fps::fromValue( - mFdp.ConsumeFloatingPoint()), - Fps::fromValue( - mFdp.ConsumeFloatingPoint())); - RefreshRateConfigs::getFrameRateDivisor(Fps::fromValue(mFdp.ConsumeFloatingPoint()), - Fps::fromValue(mFdp.ConsumeFloatingPoint())); + RefreshRateSelector::isFractionalPairOrMultiple(Fps::fromValue( + mFdp.ConsumeFloatingPoint()), + Fps::fromValue( + mFdp.ConsumeFloatingPoint())); + RefreshRateSelector::getFrameRateDivisor(Fps::fromValue(mFdp.ConsumeFloatingPoint()), + Fps::fromValue(mFdp.ConsumeFloatingPoint())); android::mock::TimeStats timeStats; RefreshRateStats refreshRateStats(timeStats, Fps::fromValue(mFdp.ConsumeFloatingPoint()), @@ -407,7 +408,7 @@ void SchedulerFuzzer::fuzzPresentLatencyTracker() { void SchedulerFuzzer::process() { fuzzRefreshRateSelection(); - fuzzRefreshRateConfigs(); + fuzzRefreshRateSelector(); fuzzPresentLatencyTracker(); fuzzVSyncModulator(); fuzzVSyncPredictor(); diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h index 1a49ead275..88e32e1bd0 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h +++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h @@ -27,7 +27,6 @@ #include "Clock.h" #include "Layer.h" #include "Scheduler/EventThread.h" -#include "Scheduler/RefreshRateConfigs.h" #include "Scheduler/Scheduler.h" #include "Scheduler/VSyncTracker.h" #include "Scheduler/VsyncModulator.h" diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index d2b58137f0..5daa398545 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -111,7 +111,7 @@ cc_test { "SurfaceFlinger_UpdateLayerMetadataSnapshotTest.cpp", "SchedulerTest.cpp", "SetFrameRateTest.cpp", - "RefreshRateConfigsTest.cpp", + "RefreshRateSelectorTest.cpp", "RefreshRateSelectionTest.cpp", "RefreshRateStatsTest.cpp", "RegionSamplingTest.cpp", diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp index 972198cbdb..979924af58 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp @@ -69,11 +69,11 @@ protected: // LayerHistory::summarize makes no guarantee of the order of the elements in the summary // however, for testing only, a stable order is required, therefore we sort the list here. // Any tests requiring ordered results must create layers with names. - auto summary = history().summarize(*mScheduler->refreshRateConfigs(), now); + auto summary = history().summarize(*mScheduler->refreshRateSelector(), now); std::sort(summary.begin(), summary.end(), - [](const RefreshRateConfigs::LayerRequirement& a, - const RefreshRateConfigs::LayerRequirement& b) -> bool { - return a.name < b.name; + [](const RefreshRateSelector::LayerRequirement& lhs, + const RefreshRateSelector::LayerRequirement& rhs) -> bool { + return lhs.name < rhs.name; }); return summary; } @@ -125,16 +125,16 @@ protected: ASSERT_EQ(desiredRefreshRate, summary[0].desiredRefreshRate); } - std::shared_ptr mConfigs = - std::make_shared(makeModes(createDisplayMode(DisplayModeId(0), - LO_FPS), - createDisplayMode(DisplayModeId(1), - HI_FPS)), - DisplayModeId(0)); + std::shared_ptr mSelector = + std::make_shared(makeModes(createDisplayMode(DisplayModeId(0), + LO_FPS), + createDisplayMode(DisplayModeId(1), + HI_FPS)), + DisplayModeId(0)); mock::SchedulerCallback mSchedulerCallback; - TestableScheduler* mScheduler = new TestableScheduler(mConfigs, mSchedulerCallback); + TestableScheduler* mScheduler = new TestableScheduler(mSelector, mSchedulerCallback); TestableSurfaceFlinger mFlinger; }; diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp deleted file mode 100644 index 924c5befde..0000000000 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ /dev/null @@ -1,2427 +0,0 @@ -/* - * Copyright 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#undef LOG_TAG -#define LOG_TAG "SchedulerUnittests" - -#include -#include - -#include -#include -#include -#include -#include - -#include "DisplayHardware/HWC2.h" -#include "FpsOps.h" -#include "Scheduler/RefreshRateConfigs.h" -#include "mock/DisplayHardware/MockDisplayMode.h" - -using namespace std::chrono_literals; - -namespace android::scheduler { - -namespace hal = android::hardware::graphics::composer::hal; - -using LayerRequirement = RefreshRateConfigs::LayerRequirement; -using LayerVoteType = RefreshRateConfigs::LayerVoteType; -using SetPolicyResult = RefreshRateConfigs::SetPolicyResult; - -using mock::createDisplayMode; - -struct TestableRefreshRateConfigs : RefreshRateConfigs { - using RefreshRateConfigs::RefreshRateOrder; - using RefreshRateConfigs::RefreshRateRanking; - - using RefreshRateConfigs::RefreshRateConfigs; - - void setActiveModeId(DisplayModeId modeId) { - ftl::FakeGuard guard(kMainThreadContext); - return RefreshRateConfigs::setActiveModeId(modeId); - } - - const DisplayMode& getActiveMode() const { - ftl::FakeGuard guard(kMainThreadContext); - return RefreshRateConfigs::getActiveMode(); - } - - DisplayModePtr getMinSupportedRefreshRate() const { - std::lock_guard lock(mLock); - return mMinRefreshRateModeIt->second; - } - - DisplayModePtr getMaxSupportedRefreshRate() const { - std::lock_guard lock(mLock); - return mMaxRefreshRateModeIt->second; - } - - DisplayModePtr getMinRefreshRateByPolicy() const { - std::lock_guard lock(mLock); - return getMinRefreshRateByPolicyLocked(); - } - - DisplayModePtr getMaxRefreshRateByPolicy() const { - std::lock_guard lock(mLock); - return getMaxRefreshRateByPolicyLocked(getActiveModeItLocked()->second->getGroup()); - } - - RefreshRateRanking rankRefreshRates(std::optional anchorGroupOpt, - RefreshRateOrder refreshRateOrder) const { - std::lock_guard lock(mLock); - return RefreshRateConfigs::rankRefreshRates(anchorGroupOpt, refreshRateOrder); - } - - const std::vector& knownFrameRates() const { return mKnownFrameRates; } - - using RefreshRateConfigs::GetRankedRefreshRatesCache; - auto& mutableGetRankedRefreshRatesCache() { return mGetRankedRefreshRatesCache; } - - auto getRankedRefreshRates(const std::vector& layers, - GlobalSignals signals) const { - const auto result = RefreshRateConfigs::getRankedRefreshRates(layers, signals); - - EXPECT_TRUE(std::is_sorted(result.ranking.begin(), result.ranking.end(), - ScoredRefreshRate::DescendingScore{})); - - return result; - } - - auto getRankedRefreshRatesAsPair(const std::vector& layers, - GlobalSignals signals) const { - const auto [ranking, consideredSignals] = getRankedRefreshRates(layers, signals); - return std::make_pair(ranking, consideredSignals); - } - - DisplayModePtr getBestRefreshRate(const std::vector& layers = {}, - GlobalSignals signals = {}) const { - return getRankedRefreshRates(layers, signals).ranking.front().modePtr; - } - - SetPolicyResult setPolicy(const PolicyVariant& policy) { - ftl::FakeGuard guard(kMainThreadContext); - return RefreshRateConfigs::setPolicy(policy); - } - - SetPolicyResult setDisplayManagerPolicy(const DisplayManagerPolicy& policy) { - return setPolicy(policy); - } -}; - -class RefreshRateConfigsTest : public testing::Test { -protected: - using RefreshRateOrder = TestableRefreshRateConfigs::RefreshRateOrder; - - RefreshRateConfigsTest(); - ~RefreshRateConfigsTest(); - - static constexpr DisplayModeId kModeId60{0}; - static constexpr DisplayModeId kModeId90{1}; - static constexpr DisplayModeId kModeId72{2}; - static constexpr DisplayModeId kModeId120{3}; - static constexpr DisplayModeId kModeId30{4}; - static constexpr DisplayModeId kModeId25{5}; - static constexpr DisplayModeId kModeId50{6}; - static constexpr DisplayModeId kModeId24{7}; - static constexpr DisplayModeId kModeId24Frac{8}; - static constexpr DisplayModeId kModeId30Frac{9}; - static constexpr DisplayModeId kModeId60Frac{10}; - - static inline const DisplayModePtr kMode60 = createDisplayMode(kModeId60, 60_Hz); - static inline const DisplayModePtr kMode60Frac = createDisplayMode(kModeId60Frac, 59.94_Hz); - static inline const DisplayModePtr kMode90 = createDisplayMode(kModeId90, 90_Hz); - static inline const DisplayModePtr kMode90_G1 = createDisplayMode(kModeId90, 90_Hz, 1); - static inline const DisplayModePtr kMode90_4K = - createDisplayMode(kModeId90, 90_Hz, 0, {3840, 2160}); - static inline const DisplayModePtr kMode72 = createDisplayMode(kModeId72, 72_Hz); - static inline const DisplayModePtr kMode72_G1 = createDisplayMode(kModeId72, 72_Hz, 1); - static inline const DisplayModePtr kMode120 = createDisplayMode(kModeId120, 120_Hz); - static inline const DisplayModePtr kMode120_G1 = createDisplayMode(kModeId120, 120_Hz, 1); - static inline const DisplayModePtr kMode30 = createDisplayMode(kModeId30, 30_Hz); - static inline const DisplayModePtr kMode30_G1 = createDisplayMode(kModeId30, 30_Hz, 1); - static inline const DisplayModePtr kMode30Frac = createDisplayMode(kModeId30Frac, 29.97_Hz); - static inline const DisplayModePtr kMode25 = createDisplayMode(kModeId25, 25_Hz); - static inline const DisplayModePtr kMode25_G1 = createDisplayMode(kModeId25, 25_Hz, 1); - static inline const DisplayModePtr kMode50 = createDisplayMode(kModeId50, 50_Hz); - static inline const DisplayModePtr kMode24 = createDisplayMode(kModeId24, 24_Hz); - static inline const DisplayModePtr kMode24Frac = createDisplayMode(kModeId24Frac, 23.976_Hz); - - // Test configurations. - static inline const DisplayModes kModes_60 = makeModes(kMode60); - static inline const DisplayModes kModes_60_90 = makeModes(kMode60, kMode90); - static inline const DisplayModes kModes_60_90_G1 = makeModes(kMode60, kMode90_G1); - static inline const DisplayModes kModes_60_90_4K = makeModes(kMode60, kMode90_4K); - static inline const DisplayModes kModes_60_72_90 = makeModes(kMode60, kMode90, kMode72); - static inline const DisplayModes kModes_60_90_72_120 = - makeModes(kMode60, kMode90, kMode72, kMode120); - static inline const DisplayModes kModes_30_60_72_90_120 = - makeModes(kMode60, kMode90, kMode72, kMode120, kMode30); - - static inline const DisplayModes kModes_30_60 = - makeModes(kMode60, kMode90_G1, kMode72_G1, kMode120_G1, kMode30); - static inline const DisplayModes kModes_30_60_72_90 = - makeModes(kMode60, kMode90, kMode72, kMode120_G1, kMode30); - static inline const DisplayModes kModes_30_60_90 = - makeModes(kMode60, kMode90, kMode72_G1, kMode120_G1, kMode30); - static inline const DisplayModes kModes_25_30_50_60 = - makeModes(kMode60, kMode90, kMode72_G1, kMode120_G1, kMode30_G1, kMode25_G1, kMode50); - static inline const DisplayModes kModes_60_120 = makeModes(kMode60, kMode120); - - // This is a typical TV configuration. - static inline const DisplayModes kModes_24_25_30_50_60_Frac = - makeModes(kMode24, kMode24Frac, kMode25, kMode30, kMode30Frac, kMode50, kMode60, - kMode60Frac); -}; - -RefreshRateConfigsTest::RefreshRateConfigsTest() { - const ::testing::TestInfo* const test_info = - ::testing::UnitTest::GetInstance()->current_test_info(); - ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); -} - -RefreshRateConfigsTest::~RefreshRateConfigsTest() { - const ::testing::TestInfo* const test_info = - ::testing::UnitTest::GetInstance()->current_test_info(); - ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); -} - -namespace { - -TEST_F(RefreshRateConfigsTest, oneMode_canSwitch) { - RefreshRateConfigs configs(kModes_60, kModeId60); - EXPECT_FALSE(configs.canSwitch()); -} - -TEST_F(RefreshRateConfigsTest, invalidPolicy) { - TestableRefreshRateConfigs configs(kModes_60, kModeId60); - - EXPECT_EQ(SetPolicyResult::Invalid, - configs.setDisplayManagerPolicy({DisplayModeId(10), {60_Hz, 60_Hz}})); - EXPECT_EQ(SetPolicyResult::Invalid, - configs.setDisplayManagerPolicy({kModeId60, {20_Hz, 40_Hz}})); -} - -TEST_F(RefreshRateConfigsTest, unchangedPolicy) { - TestableRefreshRateConfigs configs(kModes_60_90, kModeId60); - - EXPECT_EQ(SetPolicyResult::Changed, - configs.setDisplayManagerPolicy({kModeId90, {60_Hz, 90_Hz}})); - - EXPECT_EQ(SetPolicyResult::Unchanged, - configs.setDisplayManagerPolicy({kModeId90, {60_Hz, 90_Hz}})); - - // Override to the same policy. - EXPECT_EQ(SetPolicyResult::Unchanged, - configs.setPolicy(RefreshRateConfigs::OverridePolicy{kModeId90, {60_Hz, 90_Hz}})); - - // Clear override to restore DisplayManagerPolicy. - EXPECT_EQ(SetPolicyResult::Unchanged, - configs.setPolicy(RefreshRateConfigs::NoOverridePolicy{})); - - EXPECT_EQ(SetPolicyResult::Changed, - configs.setDisplayManagerPolicy({kModeId90, {30_Hz, 90_Hz}})); -} - -TEST_F(RefreshRateConfigsTest, twoModes_storesFullRefreshRateMap) { - TestableRefreshRateConfigs configs(kModes_60_90, kModeId60); - - const auto minRate = configs.getMinSupportedRefreshRate(); - const auto performanceRate = configs.getMaxSupportedRefreshRate(); - - EXPECT_EQ(kMode60, minRate); - EXPECT_EQ(kMode90, performanceRate); - - const auto minRateByPolicy = configs.getMinRefreshRateByPolicy(); - const auto performanceRateByPolicy = configs.getMaxRefreshRateByPolicy(); - - EXPECT_EQ(minRateByPolicy, minRate); - EXPECT_EQ(performanceRateByPolicy, performanceRate); -} - -TEST_F(RefreshRateConfigsTest, twoModes_storesFullRefreshRateMap_differentGroups) { - TestableRefreshRateConfigs configs(kModes_60_90_G1, kModeId60); - - const auto minRate = configs.getMinRefreshRateByPolicy(); - const auto performanceRate = configs.getMaxSupportedRefreshRate(); - const auto minRate60 = configs.getMinRefreshRateByPolicy(); - const auto performanceRate60 = configs.getMaxRefreshRateByPolicy(); - - EXPECT_EQ(kMode60, minRate); - EXPECT_EQ(kMode60, minRate60); - EXPECT_EQ(kMode60, performanceRate60); - - EXPECT_EQ(SetPolicyResult::Changed, - configs.setDisplayManagerPolicy({kModeId90, {60_Hz, 90_Hz}})); - configs.setActiveModeId(kModeId90); - - const auto minRate90 = configs.getMinRefreshRateByPolicy(); - const auto performanceRate90 = configs.getMaxRefreshRateByPolicy(); - - EXPECT_EQ(kMode90_G1, performanceRate); - EXPECT_EQ(kMode90_G1, minRate90); - EXPECT_EQ(kMode90_G1, performanceRate90); -} - -TEST_F(RefreshRateConfigsTest, twoModes_storesFullRefreshRateMap_differentResolutions) { - TestableRefreshRateConfigs configs(kModes_60_90_4K, kModeId60); - - const auto minRate = configs.getMinRefreshRateByPolicy(); - const auto performanceRate = configs.getMaxSupportedRefreshRate(); - const auto minRate60 = configs.getMinRefreshRateByPolicy(); - const auto performanceRate60 = configs.getMaxRefreshRateByPolicy(); - - EXPECT_EQ(kMode60, minRate); - EXPECT_EQ(kMode60, minRate60); - EXPECT_EQ(kMode60, performanceRate60); - - EXPECT_EQ(SetPolicyResult::Changed, - configs.setDisplayManagerPolicy({kModeId90, {60_Hz, 90_Hz}})); - configs.setActiveModeId(kModeId90); - - const auto minRate90 = configs.getMinRefreshRateByPolicy(); - const auto performanceRate90 = configs.getMaxRefreshRateByPolicy(); - - EXPECT_EQ(kMode90_4K, performanceRate); - EXPECT_EQ(kMode90_4K, minRate90); - EXPECT_EQ(kMode90_4K, performanceRate90); -} - -TEST_F(RefreshRateConfigsTest, twoModes_policyChange) { - TestableRefreshRateConfigs configs(kModes_60_90, kModeId60); - - const auto minRate = configs.getMinRefreshRateByPolicy(); - const auto performanceRate = configs.getMaxRefreshRateByPolicy(); - - EXPECT_EQ(kMode60, minRate); - EXPECT_EQ(kMode90, performanceRate); - - EXPECT_EQ(SetPolicyResult::Changed, - configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}})); - - const auto minRate60 = configs.getMinRefreshRateByPolicy(); - const auto performanceRate60 = configs.getMaxRefreshRateByPolicy(); - - EXPECT_EQ(kMode60, minRate60); - EXPECT_EQ(kMode60, performanceRate60); -} - -TEST_F(RefreshRateConfigsTest, twoModes_getActiveMode) { - TestableRefreshRateConfigs configs(kModes_60_90, kModeId60); - { - const auto& mode = configs.getActiveMode(); - EXPECT_EQ(mode.getId(), kModeId60); - } - - configs.setActiveModeId(kModeId90); - { - const auto& mode = configs.getActiveMode(); - EXPECT_EQ(mode.getId(), kModeId90); - } - - EXPECT_EQ(SetPolicyResult::Changed, - configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}})); - { - const auto& mode = configs.getActiveMode(); - EXPECT_EQ(mode.getId(), kModeId90); - } -} - -TEST_F(RefreshRateConfigsTest, getBestRefreshRate_noLayers) { - { - TestableRefreshRateConfigs configs(kModes_60_72_90, kModeId72); - - // If there are no layers we select the default frame rate, which is the max of the primary - // range. - EXPECT_EQ(kMode90, configs.getBestRefreshRate()); - - EXPECT_EQ(SetPolicyResult::Changed, - configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}})); - EXPECT_EQ(kMode60, configs.getBestRefreshRate()); - } - { - // We select max even when this will cause a non-seamless switch. - TestableRefreshRateConfigs configs(kModes_60_90_G1, kModeId60); - constexpr bool kAllowGroupSwitching = true; - EXPECT_EQ(SetPolicyResult::Changed, - configs.setDisplayManagerPolicy( - {kModeId90, kAllowGroupSwitching, {0_Hz, 90_Hz}})); - EXPECT_EQ(kMode90_G1, configs.getBestRefreshRate()); - } -} - -TEST_F(RefreshRateConfigsTest, getBestRefreshRate_exactDontChangeRefreshRateWhenNotInPolicy) { - TestableRefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId72); - - std::vector layers = {{.weight = 1.f}}; - layers[0].vote = LayerVoteType::ExplicitExact; - layers[0].desiredRefreshRate = 120_Hz; - - EXPECT_EQ(SetPolicyResult::Changed, - configs.setDisplayManagerPolicy({kModeId72, {0_Hz, 90_Hz}})); - EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers)); -} - -TEST_F(RefreshRateConfigsTest, getBestRefreshRate_60_90) { - TestableRefreshRateConfigs configs(kModes_60_90, kModeId60); - - std::vector layers = {{.weight = 1.f}}; - auto& lr = layers[0]; - - lr.vote = LayerVoteType::Min; - lr.name = "Min"; - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); - - lr.vote = LayerVoteType::Max; - lr.name = "Max"; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 90_Hz; - lr.vote = LayerVoteType::Heuristic; - lr.name = "90Hz Heuristic"; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 60_Hz; - lr.name = "60Hz Heuristic"; - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 45_Hz; - lr.name = "45Hz Heuristic"; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 30_Hz; - lr.name = "30Hz Heuristic"; - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 24_Hz; - lr.name = "24Hz Heuristic"; - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); - - lr.name = ""; - EXPECT_EQ(SetPolicyResult::Changed, - configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}})); - - lr.vote = LayerVoteType::Min; - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); - - lr.vote = LayerVoteType::Max; - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 90_Hz; - lr.vote = LayerVoteType::Heuristic; - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 60_Hz; - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 45_Hz; - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 30_Hz; - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 24_Hz; - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); - - EXPECT_EQ(SetPolicyResult::Changed, - configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}})); - - lr.vote = LayerVoteType::Min; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr.vote = LayerVoteType::Max; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 90_Hz; - lr.vote = LayerVoteType::Heuristic; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 60_Hz; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 45_Hz; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 30_Hz; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 24_Hz; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - EXPECT_EQ(SetPolicyResult::Changed, - configs.setDisplayManagerPolicy({kModeId60, {0_Hz, 120_Hz}})); - lr.vote = LayerVoteType::Min; - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); - - lr.vote = LayerVoteType::Max; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 90_Hz; - lr.vote = LayerVoteType::Heuristic; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 60_Hz; - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 45_Hz; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 30_Hz; - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 24_Hz; - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); -} - -TEST_F(RefreshRateConfigsTest, getBestRefreshRate_multipleThreshold_60_90) { - TestableRefreshRateConfigs configs(kModes_60_90, kModeId60, {.frameRateMultipleThreshold = 90}); - - std::vector layers = {{.weight = 1.f}}; - auto& lr = layers[0]; - - lr.vote = LayerVoteType::Min; - lr.name = "Min"; - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); - - lr.vote = LayerVoteType::Max; - lr.name = "Max"; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 90_Hz; - lr.vote = LayerVoteType::Heuristic; - lr.name = "90Hz Heuristic"; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 60_Hz; - lr.name = "60Hz Heuristic"; - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 45_Hz; - lr.name = "45Hz Heuristic"; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 30_Hz; - lr.name = "30Hz Heuristic"; - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 24_Hz; - lr.name = "24Hz Heuristic"; - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); -} - -TEST_F(RefreshRateConfigsTest, getBestRefreshRate_60_72_90) { - TestableRefreshRateConfigs configs(kModes_60_72_90, kModeId60); - - std::vector layers = {{.weight = 1.f}}; - auto& lr = layers[0]; - - lr.vote = LayerVoteType::Min; - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); - - lr.vote = LayerVoteType::Max; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 90_Hz; - lr.vote = LayerVoteType::Heuristic; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 60_Hz; - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 45_Hz; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 30_Hz; - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 24_Hz; - EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers)); -} - -TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_72_90_120) { - TestableRefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId60); - - std::vector layers = {{.weight = 1.f}, {.weight = 1.f}}; - auto& lr1 = layers[0]; - auto& lr2 = layers[1]; - - lr1.desiredRefreshRate = 24_Hz; - lr1.vote = LayerVoteType::Heuristic; - lr2.desiredRefreshRate = 60_Hz; - lr2.vote = LayerVoteType::Heuristic; - EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers)); - - lr1.desiredRefreshRate = 24_Hz; - lr1.vote = LayerVoteType::Heuristic; - lr2.desiredRefreshRate = 48_Hz; - lr2.vote = LayerVoteType::Heuristic; - EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers)); - - lr1.desiredRefreshRate = 24_Hz; - lr1.vote = LayerVoteType::Heuristic; - lr2.desiredRefreshRate = 48_Hz; - lr2.vote = LayerVoteType::Heuristic; - EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers)); -} - -TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes) { - TestableRefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId60); - - std::vector layers = {{.weight = 1.f}, {.weight = 1.f}}; - auto& lr1 = layers[0]; - auto& lr2 = layers[1]; - - lr1.desiredRefreshRate = 24_Hz; - lr1.vote = LayerVoteType::ExplicitDefault; - lr1.name = "24Hz ExplicitDefault"; - lr2.desiredRefreshRate = 60_Hz; - lr2.vote = LayerVoteType::Heuristic; - lr2.name = "60Hz Heuristic"; - EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers)); - - lr1.desiredRefreshRate = 24_Hz; - lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.name = "24Hz ExplicitExactOrMultiple"; - lr2.desiredRefreshRate = 60_Hz; - lr2.vote = LayerVoteType::Heuristic; - lr2.name = "60Hz Heuristic"; - EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers)); - - lr1.desiredRefreshRate = 24_Hz; - lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.name = "24Hz ExplicitExactOrMultiple"; - lr2.desiredRefreshRate = 60_Hz; - lr2.vote = LayerVoteType::ExplicitDefault; - lr2.name = "60Hz ExplicitDefault"; - EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers)); - - lr1.desiredRefreshRate = 24_Hz; - lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.name = "24Hz ExplicitExactOrMultiple"; - lr2.desiredRefreshRate = 90_Hz; - lr2.vote = LayerVoteType::Heuristic; - lr2.name = "90Hz Heuristic"; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr1.desiredRefreshRate = 24_Hz; - lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.name = "24Hz ExplicitExactOrMultiple"; - lr2.desiredRefreshRate = 90_Hz; - lr2.vote = LayerVoteType::ExplicitDefault; - lr2.name = "90Hz Heuristic"; - EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers)); - - lr1.desiredRefreshRate = 24_Hz; - lr1.vote = LayerVoteType::ExplicitDefault; - lr1.name = "24Hz ExplicitDefault"; - lr2.desiredRefreshRate = 90_Hz; - lr2.vote = LayerVoteType::Heuristic; - lr2.name = "90Hz Heuristic"; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr1.desiredRefreshRate = 24_Hz; - lr1.vote = LayerVoteType::Heuristic; - lr1.name = "24Hz Heuristic"; - lr2.desiredRefreshRate = 90_Hz; - lr2.vote = LayerVoteType::ExplicitDefault; - lr2.name = "90Hz ExplicitDefault"; - EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers)); - - lr1.desiredRefreshRate = 24_Hz; - lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.name = "24Hz ExplicitExactOrMultiple"; - lr2.desiredRefreshRate = 90_Hz; - lr2.vote = LayerVoteType::ExplicitDefault; - lr2.name = "90Hz ExplicitDefault"; - EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers)); - - lr1.desiredRefreshRate = 24_Hz; - lr1.vote = LayerVoteType::ExplicitDefault; - lr1.name = "24Hz ExplicitDefault"; - lr2.desiredRefreshRate = 90_Hz; - lr2.vote = LayerVoteType::ExplicitExactOrMultiple; - lr2.name = "90Hz ExplicitExactOrMultiple"; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); -} - -TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes_multipleThreshold) { - TestableRefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId60, - {.frameRateMultipleThreshold = 120}); - - std::vector layers = {{.weight = 1.f}, {.weight = 1.f}, {.weight = 1.f}}; - auto& lr1 = layers[0]; - auto& lr2 = layers[1]; - auto& lr3 = layers[2]; - - lr1.desiredRefreshRate = 24_Hz; - lr1.vote = LayerVoteType::ExplicitDefault; - lr1.name = "24Hz ExplicitDefault"; - lr2.desiredRefreshRate = 60_Hz; - lr2.vote = LayerVoteType::Heuristic; - lr2.name = "60Hz Heuristic"; - EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers)); - - lr1.desiredRefreshRate = 24_Hz; - lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.name = "24Hz ExplicitExactOrMultiple"; - lr2.desiredRefreshRate = 60_Hz; - lr2.vote = LayerVoteType::Heuristic; - lr2.name = "60Hz Heuristic"; - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); - - lr1.desiredRefreshRate = 24_Hz; - lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.name = "24Hz ExplicitExactOrMultiple"; - lr2.desiredRefreshRate = 60_Hz; - lr2.vote = LayerVoteType::ExplicitDefault; - lr2.name = "60Hz ExplicitDefault"; - EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers)); - - lr1.desiredRefreshRate = 24_Hz; - lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.name = "24Hz ExplicitExactOrMultiple"; - lr2.desiredRefreshRate = 90_Hz; - lr2.vote = LayerVoteType::Heuristic; - lr2.name = "90Hz Heuristic"; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr1.desiredRefreshRate = 24_Hz; - lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.name = "24Hz ExplicitExactOrMultiple"; - lr2.desiredRefreshRate = 90_Hz; - lr2.vote = LayerVoteType::ExplicitDefault; - lr2.name = "90Hz Heuristic"; - EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers)); - - lr1.desiredRefreshRate = 24_Hz; - lr1.vote = LayerVoteType::ExplicitDefault; - lr1.name = "24Hz ExplicitDefault"; - lr2.desiredRefreshRate = 90_Hz; - lr2.vote = LayerVoteType::Heuristic; - lr2.name = "90Hz Heuristic"; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr1.desiredRefreshRate = 24_Hz; - lr1.vote = LayerVoteType::Heuristic; - lr1.name = "24Hz Heuristic"; - lr2.desiredRefreshRate = 90_Hz; - lr2.vote = LayerVoteType::ExplicitDefault; - lr2.name = "90Hz ExplicitDefault"; - EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers)); - - lr1.desiredRefreshRate = 24_Hz; - lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.name = "24Hz ExplicitExactOrMultiple"; - lr2.desiredRefreshRate = 90_Hz; - lr2.vote = LayerVoteType::ExplicitDefault; - lr2.name = "90Hz ExplicitDefault"; - EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers)); - - lr1.desiredRefreshRate = 24_Hz; - lr1.vote = LayerVoteType::ExplicitDefault; - lr1.name = "24Hz ExplicitDefault"; - lr2.desiredRefreshRate = 90_Hz; - lr2.vote = LayerVoteType::ExplicitExactOrMultiple; - lr2.name = "90Hz ExplicitExactOrMultiple"; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr1.desiredRefreshRate = 24_Hz; - lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.name = "24Hz ExplicitExactOrMultiple"; - lr2.vote = LayerVoteType::Max; - lr2.name = "Max"; - EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers)); - - lr1.desiredRefreshRate = 24_Hz; - lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.name = "24Hz ExplicitExactOrMultiple"; - lr2.desiredRefreshRate = 120_Hz; - lr2.vote = LayerVoteType::ExplicitDefault; - lr2.name = "120Hz ExplicitDefault"; - EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers)); - - lr1.desiredRefreshRate = 24_Hz; - lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.name = "24Hz ExplicitExactOrMultiple"; - lr2.desiredRefreshRate = 120_Hz; - lr2.vote = LayerVoteType::ExplicitExact; - lr2.name = "120Hz ExplicitExact"; - EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers)); - - lr1.desiredRefreshRate = 10_Hz; - lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.name = "30Hz ExplicitExactOrMultiple"; - lr2.desiredRefreshRate = 120_Hz; - lr2.vote = LayerVoteType::Heuristic; - lr2.name = "120Hz ExplicitExact"; - EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers)); - - lr1.desiredRefreshRate = 30_Hz; - lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.name = "30Hz ExplicitExactOrMultiple"; - lr2.desiredRefreshRate = 30_Hz; - lr2.vote = LayerVoteType::ExplicitExactOrMultiple; - lr2.name = "30Hz ExplicitExactOrMultiple"; - lr3.vote = LayerVoteType::Heuristic; - lr3.desiredRefreshRate = 120_Hz; - lr3.name = "120Hz Heuristic"; - EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers)); -} - -TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60) { - TestableRefreshRateConfigs configs(kModes_30_60, kModeId60); - - std::vector layers = {{.weight = 1.f}}; - auto& lr = layers[0]; - - lr.vote = LayerVoteType::Min; - EXPECT_EQ(kMode30, configs.getBestRefreshRate(layers)); - - lr.vote = LayerVoteType::Max; - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 90_Hz; - lr.vote = LayerVoteType::Heuristic; - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 60_Hz; - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 45_Hz; - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 30_Hz; - EXPECT_EQ(kMode30, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 24_Hz; - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); -} - -TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_72_90) { - TestableRefreshRateConfigs configs(kModes_30_60_72_90, kModeId60); - - std::vector layers = {{.weight = 1.f}}; - auto& lr = layers[0]; - - lr.vote = LayerVoteType::Min; - lr.name = "Min"; - EXPECT_EQ(kMode30, configs.getBestRefreshRate(layers)); - - lr.vote = LayerVoteType::Max; - lr.name = "Max"; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 90_Hz; - lr.vote = LayerVoteType::Heuristic; - lr.name = "90Hz Heuristic"; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr.desiredRefreshRate = 60_Hz; - lr.name = "60Hz Heuristic"; - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers, {.touch = true})); - - lr.desiredRefreshRate = 45_Hz; - lr.name = "45Hz Heuristic"; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers, {.touch = true})); - - lr.desiredRefreshRate = 30_Hz; - lr.name = "30Hz Heuristic"; - EXPECT_EQ(kMode30, configs.getBestRefreshRate(layers)); - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers, {.touch = true})); - - lr.desiredRefreshRate = 24_Hz; - lr.name = "24Hz Heuristic"; - EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers)); - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers, {.touch = true})); - - lr.desiredRefreshRate = 24_Hz; - lr.vote = LayerVoteType::ExplicitExactOrMultiple; - lr.name = "24Hz ExplicitExactOrMultiple"; - EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers)); - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers, {.touch = true})); -} - -TEST_F(RefreshRateConfigsTest, getBestRefreshRate_PriorityTest) { - TestableRefreshRateConfigs configs(kModes_30_60_90, kModeId60); - - std::vector layers = {{.weight = 1.f}, {.weight = 1.f}}; - auto& lr1 = layers[0]; - auto& lr2 = layers[1]; - - lr1.vote = LayerVoteType::Min; - lr2.vote = LayerVoteType::Max; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr1.vote = LayerVoteType::Min; - lr2.vote = LayerVoteType::Heuristic; - lr2.desiredRefreshRate = 24_Hz; - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); - - lr1.vote = LayerVoteType::Min; - lr2.vote = LayerVoteType::ExplicitExactOrMultiple; - lr2.desiredRefreshRate = 24_Hz; - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); - - lr1.vote = LayerVoteType::Max; - lr2.vote = LayerVoteType::Heuristic; - lr2.desiredRefreshRate = 60_Hz; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr1.vote = LayerVoteType::Max; - lr2.vote = LayerVoteType::ExplicitExactOrMultiple; - lr2.desiredRefreshRate = 60_Hz; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr1.vote = LayerVoteType::Heuristic; - lr1.desiredRefreshRate = 15_Hz; - lr2.vote = LayerVoteType::Heuristic; - lr2.desiredRefreshRate = 45_Hz; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr1.vote = LayerVoteType::Heuristic; - lr1.desiredRefreshRate = 30_Hz; - lr2.vote = LayerVoteType::ExplicitExactOrMultiple; - lr2.desiredRefreshRate = 45_Hz; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); -} - -TEST_F(RefreshRateConfigsTest, getBestRefreshRate_24FpsVideo) { - TestableRefreshRateConfigs configs(kModes_60_90, kModeId60); - - std::vector layers = {{.weight = 1.f}}; - auto& lr = layers[0]; - - lr.vote = LayerVoteType::ExplicitExactOrMultiple; - for (float fps = 23.0f; fps < 25.0f; fps += 0.1f) { - lr.desiredRefreshRate = Fps::fromValue(fps); - const auto mode = configs.getBestRefreshRate(layers); - EXPECT_EQ(kMode60, mode) << lr.desiredRefreshRate << " chooses " - << to_string(mode->getFps()); - } -} - -TEST_F(RefreshRateConfigsTest, getBestRefreshRate_24FpsVideo_multipleThreshold_60_120) { - TestableRefreshRateConfigs configs(kModes_60_120, kModeId60, - {.frameRateMultipleThreshold = 120}); - - std::vector layers = {{.weight = 1.f}}; - auto& lr = layers[0]; - - lr.vote = LayerVoteType::ExplicitExactOrMultiple; - for (float fps = 23.0f; fps < 25.0f; fps += 0.1f) { - lr.desiredRefreshRate = Fps::fromValue(fps); - const auto mode = configs.getBestRefreshRate(layers); - EXPECT_EQ(kMode60, mode) << lr.desiredRefreshRate << " chooses " - << to_string(mode->getFps()); - } -} - -TEST_F(RefreshRateConfigsTest, twoModes_getBestRefreshRate_Explicit) { - TestableRefreshRateConfigs configs(kModes_60_90, kModeId60); - - std::vector layers = {{.weight = 1.f}, {.weight = 1.f}}; - auto& lr1 = layers[0]; - auto& lr2 = layers[1]; - - lr1.vote = LayerVoteType::Heuristic; - lr1.desiredRefreshRate = 60_Hz; - lr2.vote = LayerVoteType::ExplicitExactOrMultiple; - lr2.desiredRefreshRate = 90_Hz; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr1.vote = LayerVoteType::ExplicitDefault; - lr1.desiredRefreshRate = 90_Hz; - lr2.vote = LayerVoteType::ExplicitExactOrMultiple; - lr2.desiredRefreshRate = 60_Hz; - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); - - lr1.vote = LayerVoteType::Heuristic; - lr1.desiredRefreshRate = 90_Hz; - lr2.vote = LayerVoteType::ExplicitExactOrMultiple; - lr2.desiredRefreshRate = 60_Hz; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); -} - -TEST_F(RefreshRateConfigsTest, getBestRefreshRate_75HzContent) { - TestableRefreshRateConfigs configs(kModes_60_90, kModeId60); - - std::vector layers = {{.weight = 1.f}}; - auto& lr = layers[0]; - - lr.vote = LayerVoteType::ExplicitExactOrMultiple; - for (float fps = 75.0f; fps < 100.0f; fps += 0.1f) { - lr.desiredRefreshRate = Fps::fromValue(fps); - const auto mode = configs.getBestRefreshRate(layers, {}); - EXPECT_EQ(kMode90, mode) << lr.desiredRefreshRate << " chooses " - << to_string(mode->getFps()); - } -} - -TEST_F(RefreshRateConfigsTest, getBestRefreshRate_Multiples) { - TestableRefreshRateConfigs configs(kModes_60_90, kModeId60); - - std::vector layers = {{.weight = 1.f}, {.weight = 1.f}}; - auto& lr1 = layers[0]; - auto& lr2 = layers[1]; - - lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.desiredRefreshRate = 60_Hz; - lr1.name = "60Hz ExplicitExactOrMultiple"; - lr2.vote = LayerVoteType::Heuristic; - lr2.desiredRefreshRate = 90_Hz; - lr2.name = "90Hz Heuristic"; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.desiredRefreshRate = 60_Hz; - lr1.name = "60Hz ExplicitExactOrMultiple"; - lr2.vote = LayerVoteType::ExplicitDefault; - lr2.desiredRefreshRate = 90_Hz; - lr2.name = "90Hz ExplicitDefault"; - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); - - lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.desiredRefreshRate = 60_Hz; - lr1.name = "60Hz ExplicitExactOrMultiple"; - lr2.vote = LayerVoteType::Max; - lr2.name = "Max"; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.desiredRefreshRate = 30_Hz; - lr1.name = "30Hz ExplicitExactOrMultiple"; - lr2.vote = LayerVoteType::Heuristic; - lr2.desiredRefreshRate = 90_Hz; - lr2.name = "90Hz Heuristic"; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.desiredRefreshRate = 30_Hz; - lr1.name = "30Hz ExplicitExactOrMultiple"; - lr2.vote = LayerVoteType::Max; - lr2.name = "Max"; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); -} - -TEST_F(RefreshRateConfigsTest, scrollWhileWatching60fps_60_90) { - TestableRefreshRateConfigs configs(kModes_60_90, kModeId60); - - std::vector layers = {{.weight = 1.f}, {.weight = 1.f}}; - auto& lr1 = layers[0]; - auto& lr2 = layers[1]; - - lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.desiredRefreshRate = 60_Hz; - lr1.name = "60Hz ExplicitExactOrMultiple"; - lr2.vote = LayerVoteType::NoVote; - lr2.name = "NoVote"; - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); - - lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.desiredRefreshRate = 60_Hz; - lr1.name = "60Hz ExplicitExactOrMultiple"; - lr2.vote = LayerVoteType::NoVote; - lr2.name = "NoVote"; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers, {.touch = true})); - - lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.desiredRefreshRate = 60_Hz; - lr1.name = "60Hz ExplicitExactOrMultiple"; - lr2.vote = LayerVoteType::Max; - lr2.name = "Max"; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers, {.touch = true})); - - lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.desiredRefreshRate = 60_Hz; - lr1.name = "60Hz ExplicitExactOrMultiple"; - lr2.vote = LayerVoteType::Max; - lr2.name = "Max"; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - // The other layer starts to provide buffers - lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.desiredRefreshRate = 60_Hz; - lr1.name = "60Hz ExplicitExactOrMultiple"; - lr2.vote = LayerVoteType::Heuristic; - lr2.desiredRefreshRate = 90_Hz; - lr2.name = "90Hz Heuristic"; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); -} - -TEST_F(RefreshRateConfigsTest, getMaxRefreshRatesByPolicy) { - // The kModes_30_60_90 contains two kMode72_G1, kMode120_G1 which are from the - // different group. - TestableRefreshRateConfigs configs(kModes_30_60_90, kModeId60); - - const auto refreshRates = configs.rankRefreshRates(configs.getActiveMode().getGroup(), - RefreshRateOrder::Descending); - - const std::array expectedRefreshRates = {kMode90, kMode60, kMode30}; - ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size()); - - for (size_t i = 0; i < expectedRefreshRates.size(); ++i) { - EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].modePtr) - << "Expected fps " << expectedRefreshRates[i]->getFps().getIntValue() - << " Actual fps " << refreshRates[i].modePtr->getFps().getIntValue(); - } -} - -TEST_F(RefreshRateConfigsTest, getMinRefreshRatesByPolicy) { - // The kModes_30_60_90 contains two kMode72_G1, kMode120_G1 which are from the - // different group. - TestableRefreshRateConfigs configs(kModes_30_60_90, kModeId60); - - const auto refreshRates = configs.rankRefreshRates(configs.getActiveMode().getGroup(), - RefreshRateOrder::Ascending); - - const std::array expectedRefreshRates = {kMode30, kMode60, kMode90}; - ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size()); - - for (size_t i = 0; i < expectedRefreshRates.size(); ++i) { - EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].modePtr) - << "Expected fps " << expectedRefreshRates[i]->getFps().getIntValue() - << " Actual fps " << refreshRates[i].modePtr->getFps().getIntValue(); - } -} - -TEST_F(RefreshRateConfigsTest, getMinRefreshRatesByPolicyOutsideTheGroup) { - // The kModes_30_60_90 contains two kMode72_G1, kMode120_G1 which are from the - // different group. - TestableRefreshRateConfigs configs(kModes_30_60_90, kModeId72); - - EXPECT_EQ(SetPolicyResult::Changed, - configs.setDisplayManagerPolicy({kModeId60, {30_Hz, 90_Hz}, {30_Hz, 90_Hz}})); - - const auto refreshRates = - configs.rankRefreshRates(/*anchorGroupOpt*/ std::nullopt, RefreshRateOrder::Ascending); - - const std::array expectedRefreshRates = {kMode30, kMode60, kMode90}; - ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size()); - - for (size_t i = 0; i < expectedRefreshRates.size(); ++i) { - EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].modePtr) - << "Expected fps " << expectedRefreshRates[i]->getFps().getIntValue() - << " Actual fps " << refreshRates[i].modePtr->getFps().getIntValue(); - } -} - -TEST_F(RefreshRateConfigsTest, getMaxRefreshRatesByPolicyOutsideTheGroup) { - // The kModes_30_60_90 contains two kMode72_G1, kMode120_G1 which are from the - // different group. - TestableRefreshRateConfigs configs(kModes_30_60_90, kModeId72); - - EXPECT_EQ(SetPolicyResult::Changed, - configs.setDisplayManagerPolicy({kModeId60, {30_Hz, 90_Hz}, {30_Hz, 90_Hz}})); - - const auto refreshRates = - configs.rankRefreshRates(/*anchorGroupOpt*/ std::nullopt, RefreshRateOrder::Descending); - - const std::array expectedRefreshRates = {kMode90, kMode60, kMode30}; - ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size()); - - for (size_t i = 0; i < expectedRefreshRates.size(); ++i) { - EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].modePtr) - << "Expected fps " << expectedRefreshRates[i]->getFps().getIntValue() - << " Actual fps " << refreshRates[i].modePtr->getFps().getIntValue(); - } -} - -TEST_F(RefreshRateConfigsTest, powerOnImminentConsidered) { - TestableRefreshRateConfigs configs(kModes_60_90, kModeId60); - - auto [refreshRates, signals] = configs.getRankedRefreshRates({}, {}); - EXPECT_FALSE(signals.powerOnImminent); - - std::array expectedRefreshRates = {kMode90, kMode60}; - ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size()); - - for (size_t i = 0; i < expectedRefreshRates.size(); ++i) { - EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].modePtr) - << "Expected fps " << expectedRefreshRates[i]->getFps().getIntValue() - << " Actual fps " << refreshRates[i].modePtr->getFps().getIntValue(); - } - - std::tie(refreshRates, signals) = - configs.getRankedRefreshRatesAsPair({}, {.powerOnImminent = true}); - EXPECT_TRUE(signals.powerOnImminent); - - ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size()); - - for (size_t i = 0; i < expectedRefreshRates.size(); ++i) { - EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].modePtr) - << "Expected fps " << expectedRefreshRates[i]->getFps().getIntValue() - << " Actual fps " << refreshRates[i].modePtr->getFps().getIntValue(); - } - - std::vector layers = {{.weight = 1.f}}; - auto& lr1 = layers[0]; - lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.desiredRefreshRate = 60_Hz; - lr1.name = "60Hz ExplicitExactOrMultiple"; - - std::tie(refreshRates, signals) = - configs.getRankedRefreshRatesAsPair(layers, {.powerOnImminent = true}); - EXPECT_TRUE(signals.powerOnImminent); - - ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size()); - - for (size_t i = 0; i < expectedRefreshRates.size(); ++i) { - EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].modePtr) - << "Expected fps " << expectedRefreshRates[i]->getFps().getIntValue() - << " Actual fps " << refreshRates[i].modePtr->getFps().getIntValue(); - } - - std::tie(refreshRates, signals) = - configs.getRankedRefreshRatesAsPair(layers, {.powerOnImminent = false}); - EXPECT_FALSE(signals.powerOnImminent); - - expectedRefreshRates = {kMode60, kMode90}; - ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size()); - - for (size_t i = 0; i < expectedRefreshRates.size(); ++i) { - EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].modePtr) - << "Expected fps " << expectedRefreshRates[i]->getFps().getIntValue() - << " Actual fps " << refreshRates[i].modePtr->getFps().getIntValue(); - } -} - -TEST_F(RefreshRateConfigsTest, touchConsidered) { - TestableRefreshRateConfigs configs(kModes_60_90, kModeId60); - - auto [_, signals] = configs.getRankedRefreshRates({}, {}); - EXPECT_FALSE(signals.touch); - - std::tie(std::ignore, signals) = configs.getRankedRefreshRatesAsPair({}, {.touch = true}); - EXPECT_TRUE(signals.touch); - - std::vector layers = {{.weight = 1.f}, {.weight = 1.f}}; - auto& lr1 = layers[0]; - auto& lr2 = layers[1]; - - lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.desiredRefreshRate = 60_Hz; - lr1.name = "60Hz ExplicitExactOrMultiple"; - lr2.vote = LayerVoteType::Heuristic; - lr2.desiredRefreshRate = 60_Hz; - lr2.name = "60Hz Heuristic"; - std::tie(std::ignore, signals) = configs.getRankedRefreshRatesAsPair(layers, {.touch = true}); - EXPECT_TRUE(signals.touch); - - lr1.vote = LayerVoteType::ExplicitDefault; - lr1.desiredRefreshRate = 60_Hz; - lr1.name = "60Hz ExplicitDefault"; - lr2.vote = LayerVoteType::Heuristic; - lr2.desiredRefreshRate = 60_Hz; - lr2.name = "60Hz Heuristic"; - std::tie(std::ignore, signals) = configs.getRankedRefreshRatesAsPair(layers, {.touch = true}); - EXPECT_FALSE(signals.touch); - - lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.desiredRefreshRate = 60_Hz; - lr1.name = "60Hz ExplicitExactOrMultiple"; - lr2.vote = LayerVoteType::Heuristic; - lr2.desiredRefreshRate = 60_Hz; - lr2.name = "60Hz Heuristic"; - std::tie(std::ignore, signals) = configs.getRankedRefreshRatesAsPair(layers, {.touch = true}); - EXPECT_TRUE(signals.touch); - - lr1.vote = LayerVoteType::ExplicitDefault; - lr1.desiredRefreshRate = 60_Hz; - lr1.name = "60Hz ExplicitDefault"; - lr2.vote = LayerVoteType::Heuristic; - lr2.desiredRefreshRate = 60_Hz; - lr2.name = "60Hz Heuristic"; - std::tie(std::ignore, signals) = configs.getRankedRefreshRatesAsPair(layers, {.touch = true}); - EXPECT_FALSE(signals.touch); -} - -TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitDefault) { - TestableRefreshRateConfigs configs(kModes_60_90_72_120, kModeId60); - - std::vector layers = {{.weight = 1.f}}; - auto& lr = layers[0]; - - // Prepare a table with the vote and the expected refresh rate - const std::initializer_list> testCases = { - {130_Hz, 120_Hz}, {120_Hz, 120_Hz}, {119_Hz, 120_Hz}, {110_Hz, 120_Hz}, - - {100_Hz, 90_Hz}, {90_Hz, 90_Hz}, {89_Hz, 90_Hz}, - - {80_Hz, 72_Hz}, {73_Hz, 72_Hz}, {72_Hz, 72_Hz}, {71_Hz, 72_Hz}, {70_Hz, 72_Hz}, - - {65_Hz, 60_Hz}, {60_Hz, 60_Hz}, {59_Hz, 60_Hz}, {58_Hz, 60_Hz}, - - {55_Hz, 90_Hz}, {50_Hz, 90_Hz}, {45_Hz, 90_Hz}, - - {42_Hz, 120_Hz}, {40_Hz, 120_Hz}, {39_Hz, 120_Hz}, - - {37_Hz, 72_Hz}, {36_Hz, 72_Hz}, {35_Hz, 72_Hz}, - - {30_Hz, 60_Hz}, - }; - - for (auto [desired, expected] : testCases) { - lr.vote = LayerVoteType::ExplicitDefault; - lr.desiredRefreshRate = desired; - - std::stringstream ss; - ss << "ExplicitDefault " << desired; - lr.name = ss.str(); - - EXPECT_EQ(expected, configs.getBestRefreshRate(layers)->getFps()); - } -} - -TEST_F(RefreshRateConfigsTest, - getBestRefreshRate_ExplicitExactOrMultiple_WithFractionalRefreshRates) { - std::vector layers = {{.weight = 1.f}}; - auto& lr = layers[0]; - - // Test that 23.976 will choose 24 if 23.976 is not supported - { - TestableRefreshRateConfigs configs(makeModes(kMode24, kMode25, kMode30, kMode30Frac, - kMode60, kMode60Frac), - kModeId60); - - lr.vote = LayerVoteType::ExplicitExactOrMultiple; - lr.desiredRefreshRate = 23.976_Hz; - lr.name = "ExplicitExactOrMultiple 23.976 Hz"; - EXPECT_EQ(kModeId24, configs.getBestRefreshRate(layers)->getId()); - } - - // Test that 24 will choose 23.976 if 24 is not supported - { - TestableRefreshRateConfigs configs(makeModes(kMode24Frac, kMode25, kMode30, kMode30Frac, - kMode60, kMode60Frac), - kModeId60); - - lr.desiredRefreshRate = 24_Hz; - lr.name = "ExplicitExactOrMultiple 24 Hz"; - EXPECT_EQ(kModeId24Frac, configs.getBestRefreshRate(layers)->getId()); - } - - // Test that 29.97 will prefer 59.94 over 60 and 30 - { - TestableRefreshRateConfigs configs(makeModes(kMode24, kMode24Frac, kMode25, kMode30, - kMode60, kMode60Frac), - kModeId60); - - lr.desiredRefreshRate = 29.97_Hz; - lr.name = "ExplicitExactOrMultiple 29.97 Hz"; - EXPECT_EQ(kModeId60Frac, configs.getBestRefreshRate(layers)->getId()); - } -} - -TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExact_WithFractionalRefreshRates) { - std::vector layers = {{.weight = 1.f}}; - auto& lr = layers[0]; - - // Test that voting for supported refresh rate will select this refresh rate - { - TestableRefreshRateConfigs configs(kModes_24_25_30_50_60_Frac, kModeId60); - - for (auto desired : {23.976_Hz, 24_Hz, 25_Hz, 29.97_Hz, 30_Hz, 50_Hz, 59.94_Hz, 60_Hz}) { - lr.vote = LayerVoteType::ExplicitExact; - lr.desiredRefreshRate = desired; - std::stringstream ss; - ss << "ExplicitExact " << desired; - lr.name = ss.str(); - - EXPECT_EQ(lr.desiredRefreshRate, configs.getBestRefreshRate(layers)->getFps()); - } - } -} - -TEST_F(RefreshRateConfigsTest, - getBestRefreshRate_withDisplayManagerRequestingSingleRate_ignoresTouchFlag) { - TestableRefreshRateConfigs configs(kModes_60_90, kModeId90); - - EXPECT_EQ(SetPolicyResult::Changed, - configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}, {60_Hz, 90_Hz}})); - - std::vector layers = {{.weight = 1.f}}; - auto& lr = layers[0]; - - lr.vote = LayerVoteType::ExplicitDefault; - lr.desiredRefreshRate = 60_Hz; - lr.name = "60Hz ExplicitDefault"; - lr.focused = true; - - const auto [mode, signals] = - configs.getRankedRefreshRates(layers, {.touch = true, .idle = true}); - - EXPECT_EQ(mode.begin()->modePtr, kMode60); - EXPECT_FALSE(signals.touch); -} - -TEST_F(RefreshRateConfigsTest, - getBestRefreshRate_withDisplayManagerRequestingSingleRate_ignoresIdleFlag) { - TestableRefreshRateConfigs configs(kModes_60_90, kModeId60); - - EXPECT_EQ(SetPolicyResult::Changed, - configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}, {60_Hz, 90_Hz}})); - - std::vector layers = {{.weight = 1.f}}; - auto& lr = layers[0]; - - lr.vote = LayerVoteType::ExplicitDefault; - lr.desiredRefreshRate = 90_Hz; - lr.name = "90Hz ExplicitDefault"; - lr.focused = true; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers, {.idle = true})); -} - -TEST_F(RefreshRateConfigsTest, testDisplayModeOrdering) { - TestableRefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId60); - - std::vector layers = {{.weight = 1.f}, - {.weight = 1.f}, - {.weight = 1.f}, - {.weight = 1.f}, - {.weight = 1.f}}; - auto& lr1 = layers[0]; - auto& lr2 = layers[1]; - auto& lr3 = layers[2]; - auto& lr4 = layers[3]; - auto& lr5 = layers[4]; - - lr1.desiredRefreshRate = 90_Hz; - lr1.name = "90Hz"; - lr1.focused = true; - - lr2.desiredRefreshRate = 60_Hz; - lr2.name = "60Hz"; - lr2.focused = true; - - lr3.desiredRefreshRate = 72_Hz; - lr3.name = "72Hz"; - lr3.focused = true; - - lr4.desiredRefreshRate = 120_Hz; - lr4.name = "120Hz"; - lr4.focused = true; - - lr5.desiredRefreshRate = 30_Hz; - lr5.name = "30Hz"; - lr5.focused = true; - - std::array expectedRanking = {kMode120, kMode90, kMode72, kMode60, kMode30}; - auto actualRanking = configs.getRankedRefreshRates(layers, {}).ranking; - - ASSERT_EQ(expectedRanking.size(), actualRanking.size()); - - for (size_t i = 0; i < expectedRanking.size(); ++i) { - EXPECT_EQ(expectedRanking[i], actualRanking[i].modePtr) - << "Expected fps " << expectedRanking[i]->getFps().getIntValue() << " Actual fps " - << actualRanking[i].modePtr->getFps().getIntValue(); - } - - lr1.vote = LayerVoteType::Max; - lr1.name = "Max"; - - lr2.desiredRefreshRate = 60_Hz; - lr2.name = "60Hz"; - - lr3.desiredRefreshRate = 72_Hz; - lr3.name = "72Hz"; - - lr4.desiredRefreshRate = 90_Hz; - lr4.name = "90Hz"; - - lr5.desiredRefreshRate = 120_Hz; - lr5.name = "120Hz"; - - expectedRanking = {kMode120, kMode90, kMode72, kMode60, kMode30}; - actualRanking = configs.getRankedRefreshRates(layers, {}).ranking; - - ASSERT_EQ(expectedRanking.size(), actualRanking.size()); - - for (size_t i = 0; i < expectedRanking.size(); ++i) { - EXPECT_EQ(expectedRanking[i], actualRanking[i].modePtr) - << "Expected fps " << expectedRanking[i]->getFps().getIntValue() << " Actual fps " - << actualRanking[i].modePtr->getFps().getIntValue(); - } - - lr1.vote = LayerVoteType::Heuristic; - lr1.desiredRefreshRate = 30_Hz; - lr1.name = "30Hz"; - - lr2.desiredRefreshRate = 120_Hz; - lr2.name = "120Hz"; - - lr3.desiredRefreshRate = 60_Hz; - lr3.name = "60Hz"; - - lr5.desiredRefreshRate = 72_Hz; - lr5.name = "72Hz"; - - expectedRanking = {kMode30, kMode60, kMode90, kMode120, kMode72}; - actualRanking = configs.getRankedRefreshRates(layers, {}).ranking; - - ASSERT_EQ(expectedRanking.size(), actualRanking.size()); - - for (size_t i = 0; i < expectedRanking.size(); ++i) { - EXPECT_EQ(expectedRanking[i], actualRanking[i].modePtr) - << "Expected fps " << expectedRanking[i]->getFps().getIntValue() << " Actual fps " - << actualRanking[i].modePtr->getFps().getIntValue(); - } - - lr1.desiredRefreshRate = 120_Hz; - lr1.name = "120Hz"; - lr1.weight = 0.0f; - - lr2.desiredRefreshRate = 60_Hz; - lr2.name = "60Hz"; - lr2.vote = LayerVoteType::NoVote; - - lr3.name = "60Hz-2"; - lr3.vote = LayerVoteType::Heuristic; - - lr4.vote = LayerVoteType::ExplicitExact; - - lr5.desiredRefreshRate = 120_Hz; - lr5.name = "120Hz-2"; - - expectedRanking = {kMode90, kMode60, kMode120, kMode72, kMode30}; - actualRanking = configs.getRankedRefreshRates(layers, {}).ranking; - - ASSERT_EQ(expectedRanking.size(), actualRanking.size()); - - for (size_t i = 0; i < expectedRanking.size(); ++i) { - EXPECT_EQ(expectedRanking[i], actualRanking[i].modePtr) - << "Expected fps " << expectedRanking[i]->getFps().getIntValue() << " Actual fps " - << actualRanking[i].modePtr->getFps().getIntValue(); - } -} - -TEST_F(RefreshRateConfigsTest, - getBestRefreshRate_withDisplayManagerRequestingSingleRate_onlySwitchesRatesForExplicitFocusedLayers) { - TestableRefreshRateConfigs configs(kModes_60_90, kModeId90); - - EXPECT_EQ(SetPolicyResult::Changed, - configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}, {60_Hz, 90_Hz}})); - - const auto [ranking, signals] = configs.getRankedRefreshRates({}, {}); - EXPECT_EQ(ranking.front().modePtr, kMode90); - EXPECT_FALSE(signals.touch); - - std::vector layers = {{.weight = 1.f}}; - auto& lr = layers[0]; - - lr.vote = LayerVoteType::ExplicitExactOrMultiple; - lr.desiredRefreshRate = 60_Hz; - lr.name = "60Hz ExplicitExactOrMultiple"; - lr.focused = false; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr.focused = true; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr.vote = LayerVoteType::ExplicitDefault; - lr.desiredRefreshRate = 60_Hz; - lr.name = "60Hz ExplicitDefault"; - lr.focused = false; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr.focused = true; - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); - - lr.vote = LayerVoteType::Heuristic; - lr.desiredRefreshRate = 60_Hz; - lr.name = "60Hz Heuristic"; - lr.focused = false; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr.focused = true; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr.vote = LayerVoteType::Max; - lr.desiredRefreshRate = 60_Hz; - lr.name = "60Hz Max"; - lr.focused = false; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr.focused = true; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr.vote = LayerVoteType::Min; - lr.desiredRefreshRate = 60_Hz; - lr.name = "60Hz Min"; - lr.focused = false; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - lr.focused = true; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); -} - -TEST_F(RefreshRateConfigsTest, groupSwitchingNotAllowed) { - TestableRefreshRateConfigs configs(kModes_60_90_G1, kModeId60); - - // The default policy doesn't allow group switching. Verify that no - // group switches are performed. - std::vector layers = {{.weight = 1.f}}; - auto& layer = layers[0]; - layer.vote = LayerVoteType::ExplicitDefault; - layer.desiredRefreshRate = 90_Hz; - layer.seamlessness = Seamlessness::SeamedAndSeamless; - layer.name = "90Hz ExplicitDefault"; - layer.focused = true; - - EXPECT_EQ(kModeId60, configs.getBestRefreshRate(layers)->getId()); -} - -TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayer) { - TestableRefreshRateConfigs configs(kModes_60_90_G1, kModeId60); - - RefreshRateConfigs::DisplayManagerPolicy policy; - policy.defaultMode = configs.getCurrentPolicy().defaultMode; - policy.allowGroupSwitching = true; - EXPECT_EQ(SetPolicyResult::Changed, configs.setPolicy(policy)); - - std::vector layers = {{.weight = 1.f}}; - auto& layer = layers[0]; - layer.vote = LayerVoteType::ExplicitDefault; - layer.desiredRefreshRate = 90_Hz; - layer.seamlessness = Seamlessness::SeamedAndSeamless; - layer.name = "90Hz ExplicitDefault"; - layer.focused = true; - EXPECT_EQ(kModeId90, configs.getBestRefreshRate(layers)->getId()); -} - -TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayerOnlySeamless) { - TestableRefreshRateConfigs configs(kModes_60_90_G1, kModeId60); - - RefreshRateConfigs::DisplayManagerPolicy policy; - policy.defaultMode = configs.getCurrentPolicy().defaultMode; - policy.allowGroupSwitching = true; - EXPECT_EQ(SetPolicyResult::Changed, configs.setPolicy(policy)); - - // Verify that we won't change the group if seamless switch is required. - std::vector layers = {{.weight = 1.f}}; - auto& layer = layers[0]; - layer.vote = LayerVoteType::ExplicitDefault; - layer.desiredRefreshRate = 90_Hz; - layer.seamlessness = Seamlessness::OnlySeamless; - layer.name = "90Hz ExplicitDefault"; - layer.focused = true; - EXPECT_EQ(kModeId60, configs.getBestRefreshRate(layers)->getId()); -} - -TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayerOnlySeamlessDefaultFps) { - TestableRefreshRateConfigs configs(kModes_60_90_G1, kModeId60); - - RefreshRateConfigs::DisplayManagerPolicy policy; - policy.defaultMode = configs.getCurrentPolicy().defaultMode; - policy.allowGroupSwitching = true; - EXPECT_EQ(SetPolicyResult::Changed, configs.setPolicy(policy)); - - configs.setActiveModeId(kModeId90); - - // Verify that we won't do a seamless switch if we request the same mode as the default - std::vector layers = {{.weight = 1.f}}; - auto& layer = layers[0]; - layer.vote = LayerVoteType::ExplicitDefault; - layer.desiredRefreshRate = 60_Hz; - layer.seamlessness = Seamlessness::OnlySeamless; - layer.name = "60Hz ExplicitDefault"; - layer.focused = true; - EXPECT_EQ(kModeId90, configs.getBestRefreshRate(layers)->getId()); -} - -TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayerDefaultSeamlessness) { - TestableRefreshRateConfigs configs(kModes_60_90_G1, kModeId60); - - RefreshRateConfigs::DisplayManagerPolicy policy; - policy.defaultMode = configs.getCurrentPolicy().defaultMode; - policy.allowGroupSwitching = true; - EXPECT_EQ(SetPolicyResult::Changed, configs.setPolicy(policy)); - - configs.setActiveModeId(kModeId90); - - // Verify that if the current config is in another group and there are no layers with - // seamlessness=SeamedAndSeamless we'll go back to the default group. - - std::vector layers = {{.weight = 1.f}}; - auto& layer = layers[0]; - layer.vote = LayerVoteType::ExplicitDefault; - layer.desiredRefreshRate = 60_Hz; - layer.seamlessness = Seamlessness::Default; - layer.name = "60Hz ExplicitDefault"; - layer.focused = true; - - EXPECT_EQ(kModeId60, configs.getBestRefreshRate(layers)->getId()); -} - -TEST_F(RefreshRateConfigsTest, groupSwitchingWithTwoLayersOnlySeamlessAndSeamed) { - TestableRefreshRateConfigs configs(kModes_60_90_G1, kModeId60); - - RefreshRateConfigs::DisplayManagerPolicy policy; - policy.defaultMode = configs.getCurrentPolicy().defaultMode; - policy.allowGroupSwitching = true; - EXPECT_EQ(SetPolicyResult::Changed, configs.setPolicy(policy)); - - configs.setActiveModeId(kModeId90); - - // If there's a layer with seamlessness=SeamedAndSeamless, another layer with - // seamlessness=OnlySeamless can't change the mode group. - std::vector layers = {{.weight = 1.f}}; - layers[0].vote = LayerVoteType::ExplicitDefault; - layers[0].desiredRefreshRate = 60_Hz; - layers[0].seamlessness = Seamlessness::OnlySeamless; - layers[0].name = "60Hz ExplicitDefault"; - layers[0].focused = true; - - layers.push_back(LayerRequirement{.weight = 0.5f}); - layers[1].vote = LayerVoteType::ExplicitDefault; - layers[1].seamlessness = Seamlessness::SeamedAndSeamless; - layers[1].desiredRefreshRate = 90_Hz; - layers[1].name = "90Hz ExplicitDefault"; - layers[1].focused = false; - - EXPECT_EQ(kModeId90, configs.getBestRefreshRate(layers)->getId()); -} - -TEST_F(RefreshRateConfigsTest, groupSwitchingWithTwoLayersDefaultFocusedAndSeamed) { - TestableRefreshRateConfigs configs(kModes_60_90_G1, kModeId60); - - RefreshRateConfigs::DisplayManagerPolicy policy; - policy.defaultMode = configs.getCurrentPolicy().defaultMode; - policy.allowGroupSwitching = true; - EXPECT_EQ(SetPolicyResult::Changed, configs.setPolicy(policy)); - - configs.setActiveModeId(kModeId90); - - // If there's a focused layer with seamlessness=SeamedAndSeamless, another layer with - // seamlessness=Default can't change the mode group back to the group of the default - // mode. - // For example, this may happen when a video playback requests and gets a seamed switch, - // but another layer (with default seamlessness) starts animating. The animating layer - // should not cause a seamed switch. - std::vector layers = {{.weight = 1.f}}; - layers[0].seamlessness = Seamlessness::Default; - layers[0].desiredRefreshRate = 60_Hz; - layers[0].focused = true; - layers[0].vote = LayerVoteType::ExplicitDefault; - layers[0].name = "60Hz ExplicitDefault"; - - layers.push_back(LayerRequirement{.weight = 0.1f}); - layers[1].seamlessness = Seamlessness::SeamedAndSeamless; - layers[1].desiredRefreshRate = 90_Hz; - layers[1].focused = true; - layers[1].vote = LayerVoteType::ExplicitDefault; - layers[1].name = "90Hz ExplicitDefault"; - - EXPECT_EQ(kModeId90, configs.getBestRefreshRate(layers)->getId()); -} - -TEST_F(RefreshRateConfigsTest, groupSwitchingWithTwoLayersDefaultNotFocusedAndSeamed) { - TestableRefreshRateConfigs configs(kModes_60_90_G1, kModeId60); - - RefreshRateConfigs::DisplayManagerPolicy policy; - policy.defaultMode = configs.getCurrentPolicy().defaultMode; - policy.allowGroupSwitching = true; - EXPECT_EQ(SetPolicyResult::Changed, configs.setPolicy(policy)); - - configs.setActiveModeId(kModeId90); - - // Layer with seamlessness=Default can change the mode group if there's a not - // focused layer with seamlessness=SeamedAndSeamless. This happens for example, - // when in split screen mode the user switches between the two visible applications. - std::vector layers = {{.weight = 1.f}}; - layers[0].seamlessness = Seamlessness::Default; - layers[0].desiredRefreshRate = 60_Hz; - layers[0].focused = true; - layers[0].vote = LayerVoteType::ExplicitDefault; - layers[0].name = "60Hz ExplicitDefault"; - - layers.push_back(LayerRequirement{.weight = 0.7f}); - layers[1].seamlessness = Seamlessness::SeamedAndSeamless; - layers[1].desiredRefreshRate = 90_Hz; - layers[1].focused = false; - layers[1].vote = LayerVoteType::ExplicitDefault; - layers[1].name = "90Hz ExplicitDefault"; - - EXPECT_EQ(kModeId60, configs.getBestRefreshRate(layers)->getId()); -} - -TEST_F(RefreshRateConfigsTest, nonSeamlessVotePrefersSeamlessSwitches) { - TestableRefreshRateConfigs configs(kModes_30_60, kModeId60); - - // Allow group switching. - RefreshRateConfigs::DisplayManagerPolicy policy; - policy.defaultMode = configs.getCurrentPolicy().defaultMode; - policy.allowGroupSwitching = true; - EXPECT_EQ(SetPolicyResult::Changed, configs.setPolicy(policy)); - - std::vector layers = {{.weight = 1.f}}; - auto& layer = layers[0]; - layer.vote = LayerVoteType::ExplicitExactOrMultiple; - layer.desiredRefreshRate = 60_Hz; - layer.seamlessness = Seamlessness::SeamedAndSeamless; - layer.name = "60Hz ExplicitExactOrMultiple"; - layer.focused = true; - - EXPECT_EQ(kModeId60, configs.getBestRefreshRate(layers)->getId()); - - configs.setActiveModeId(kModeId120); - EXPECT_EQ(kModeId120, configs.getBestRefreshRate(layers)->getId()); -} - -TEST_F(RefreshRateConfigsTest, nonSeamlessExactAndSeamlessMultipleLayers) { - TestableRefreshRateConfigs configs(kModes_25_30_50_60, kModeId60); - - // Allow group switching. - RefreshRateConfigs::DisplayManagerPolicy policy; - policy.defaultMode = configs.getCurrentPolicy().defaultMode; - policy.allowGroupSwitching = true; - EXPECT_EQ(SetPolicyResult::Changed, configs.setPolicy(policy)); - - std::vector layers = {{.name = "60Hz ExplicitDefault", - .vote = LayerVoteType::ExplicitDefault, - .desiredRefreshRate = 60_Hz, - .seamlessness = Seamlessness::SeamedAndSeamless, - .weight = 0.5f, - .focused = false}, - {.name = "25Hz ExplicitExactOrMultiple", - .vote = LayerVoteType::ExplicitExactOrMultiple, - .desiredRefreshRate = 25_Hz, - .seamlessness = Seamlessness::OnlySeamless, - .weight = 1.f, - .focused = true}}; - - EXPECT_EQ(kModeId50, configs.getBestRefreshRate(layers)->getId()); - - auto& seamedLayer = layers[0]; - seamedLayer.desiredRefreshRate = 30_Hz; - seamedLayer.name = "30Hz ExplicitDefault"; - configs.setActiveModeId(kModeId30); - - EXPECT_EQ(kModeId25, configs.getBestRefreshRate(layers)->getId()); -} - -TEST_F(RefreshRateConfigsTest, minLayersDontTrigerSeamedSwitch) { - TestableRefreshRateConfigs configs(kModes_60_90_G1, kModeId90); - - // Allow group switching. - RefreshRateConfigs::DisplayManagerPolicy policy; - policy.defaultMode = configs.getCurrentPolicy().defaultMode; - policy.allowGroupSwitching = true; - EXPECT_EQ(SetPolicyResult::Changed, configs.setPolicy(policy)); - - std::vector layers = { - {.name = "Min", .vote = LayerVoteType::Min, .weight = 1.f, .focused = true}}; - - EXPECT_EQ(kModeId90, configs.getBestRefreshRate(layers)->getId()); -} - -TEST_F(RefreshRateConfigsTest, primaryVsAppRequestPolicy) { - TestableRefreshRateConfigs configs(kModes_30_60_90, kModeId60); - - std::vector layers = {{.weight = 1.f}}; - layers[0].name = "Test layer"; - - struct Args { - bool touch = false; - bool focused = true; - }; - - // Return the config ID from calling getBestRefreshRate() for a single layer with the - // given voteType and fps. - auto getFrameRate = [&](LayerVoteType voteType, Fps fps, Args args = {}) -> DisplayModeId { - layers[0].vote = voteType; - layers[0].desiredRefreshRate = fps; - layers[0].focused = args.focused; - return configs.getBestRefreshRate(layers, {.touch = args.touch})->getId(); - }; - - EXPECT_EQ(SetPolicyResult::Changed, - configs.setDisplayManagerPolicy({kModeId60, {30_Hz, 60_Hz}, {30_Hz, 90_Hz}})); - - EXPECT_EQ(kModeId60, configs.getBestRefreshRate()->getId()); - EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::NoVote, 90_Hz)); - EXPECT_EQ(kModeId30, getFrameRate(LayerVoteType::Min, 90_Hz)); - EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::Max, 90_Hz)); - EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::Heuristic, 90_Hz)); - EXPECT_EQ(kModeId90, getFrameRate(LayerVoteType::ExplicitDefault, 90_Hz)); - EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90_Hz)); - - // Unfocused layers are not allowed to override primary config. - EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::ExplicitDefault, 90_Hz, {.focused = false})); - EXPECT_EQ(kModeId60, - getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90_Hz, {.focused = false})); - - // Touch boost should be restricted to the primary range. - EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::Max, 90_Hz, {.touch = true})); - - // When we're higher than the primary range max due to a layer frame rate setting, touch boost - // shouldn't drag us back down to the primary range max. - EXPECT_EQ(kModeId90, getFrameRate(LayerVoteType::ExplicitDefault, 90_Hz, {.touch = true})); - EXPECT_EQ(kModeId60, - getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90_Hz, {.touch = true})); - - EXPECT_EQ(SetPolicyResult::Changed, - configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}, {60_Hz, 60_Hz}})); - - EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::NoVote, 90_Hz)); - EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::Min, 90_Hz)); - EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::Max, 90_Hz)); - EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::Heuristic, 90_Hz)); - EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::ExplicitDefault, 90_Hz)); - EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90_Hz)); -} - -TEST_F(RefreshRateConfigsTest, idle) { - TestableRefreshRateConfigs configs(kModes_60_90, kModeId60); - - std::vector layers = {{.weight = 1.f}}; - layers[0].name = "Test layer"; - - const auto getIdleFrameRate = [&](LayerVoteType voteType, bool touchActive) -> DisplayModeId { - layers[0].vote = voteType; - layers[0].desiredRefreshRate = 90_Hz; - - const auto [ranking, signals] = - configs.getRankedRefreshRates(layers, {.touch = touchActive, .idle = true}); - - // Refresh rate will be chosen by either touch state or idle state. - EXPECT_EQ(!touchActive, signals.idle); - return ranking.front().modePtr->getId(); - }; - - EXPECT_EQ(SetPolicyResult::Changed, - configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 90_Hz}, {60_Hz, 90_Hz}})); - - // Idle should be lower priority than touch boost. - { - constexpr bool kTouchActive = true; - EXPECT_EQ(kModeId90, getIdleFrameRate(LayerVoteType::NoVote, kTouchActive)); - EXPECT_EQ(kModeId90, getIdleFrameRate(LayerVoteType::Min, kTouchActive)); - EXPECT_EQ(kModeId90, getIdleFrameRate(LayerVoteType::Max, kTouchActive)); - EXPECT_EQ(kModeId90, getIdleFrameRate(LayerVoteType::Heuristic, kTouchActive)); - EXPECT_EQ(kModeId90, getIdleFrameRate(LayerVoteType::ExplicitDefault, kTouchActive)); - EXPECT_EQ(kModeId90, - getIdleFrameRate(LayerVoteType::ExplicitExactOrMultiple, kTouchActive)); - } - - // With no layers, idle should still be lower priority than touch boost. - EXPECT_EQ(kModeId90, configs.getBestRefreshRate({}, {.touch = true, .idle = true})->getId()); - - // Idle should be higher precedence than other layer frame rate considerations. - configs.setActiveModeId(kModeId90); - - { - constexpr bool kTouchActive = false; - EXPECT_EQ(kModeId60, getIdleFrameRate(LayerVoteType::NoVote, kTouchActive)); - EXPECT_EQ(kModeId60, getIdleFrameRate(LayerVoteType::Min, kTouchActive)); - EXPECT_EQ(kModeId60, getIdleFrameRate(LayerVoteType::Max, kTouchActive)); - EXPECT_EQ(kModeId60, getIdleFrameRate(LayerVoteType::Heuristic, kTouchActive)); - EXPECT_EQ(kModeId60, getIdleFrameRate(LayerVoteType::ExplicitDefault, kTouchActive)); - EXPECT_EQ(kModeId60, - getIdleFrameRate(LayerVoteType::ExplicitExactOrMultiple, kTouchActive)); - } - - // Idle should be applied rather than the current config when there are no layers. - EXPECT_EQ(kModeId60, configs.getBestRefreshRate({}, {.idle = true})->getId()); -} - -TEST_F(RefreshRateConfigsTest, findClosestKnownFrameRate) { - TestableRefreshRateConfigs configs(kModes_60_90, kModeId60); - - for (float fps = 1.0f; fps <= 120.0f; fps += 0.1f) { - const auto knownFrameRate = configs.findClosestKnownFrameRate(Fps::fromValue(fps)); - const Fps expectedFrameRate = [fps] { - if (fps < 26.91f) return 24_Hz; - if (fps < 37.51f) return 30_Hz; - if (fps < 52.51f) return 45_Hz; - if (fps < 66.01f) return 60_Hz; - if (fps < 81.01f) return 72_Hz; - return 90_Hz; - }(); - - EXPECT_EQ(expectedFrameRate, knownFrameRate); - } -} - -TEST_F(RefreshRateConfigsTest, getBestRefreshRate_KnownFrameRate) { - TestableRefreshRateConfigs configs(kModes_60_90, kModeId60); - - struct Expectation { - Fps fps; - DisplayModePtr mode; - }; - - const std::initializer_list knownFrameRatesExpectations = { - {24_Hz, kMode60}, {30_Hz, kMode60}, {45_Hz, kMode90}, - {60_Hz, kMode60}, {72_Hz, kMode90}, {90_Hz, kMode90}, - }; - - // Make sure the test tests all the known frame rate - const auto& knownFrameRates = configs.knownFrameRates(); - const bool equal = std::equal(knownFrameRates.begin(), knownFrameRates.end(), - knownFrameRatesExpectations.begin(), - [](Fps fps, const Expectation& expected) { - return isApproxEqual(fps, expected.fps); - }); - EXPECT_TRUE(equal); - - std::vector layers = {{.weight = 1.f}}; - auto& layer = layers[0]; - layer.vote = LayerVoteType::Heuristic; - - for (const auto& [fps, mode] : knownFrameRatesExpectations) { - layer.desiredRefreshRate = fps; - EXPECT_EQ(mode, configs.getBestRefreshRate(layers)); - } -} - -TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExact) { - TestableRefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId60); - - std::vector layers = {{.weight = 1.f}, {.weight = 0.5f}}; - auto& explicitExactLayer = layers[0]; - auto& explicitExactOrMultipleLayer = layers[1]; - - explicitExactOrMultipleLayer.vote = LayerVoteType::ExplicitExactOrMultiple; - explicitExactOrMultipleLayer.name = "ExplicitExactOrMultiple"; - explicitExactOrMultipleLayer.desiredRefreshRate = 60_Hz; - - explicitExactLayer.vote = LayerVoteType::ExplicitExact; - explicitExactLayer.name = "ExplicitExact"; - explicitExactLayer.desiredRefreshRate = 30_Hz; - - EXPECT_EQ(kMode30, configs.getBestRefreshRate(layers)); - EXPECT_EQ(kMode30, configs.getBestRefreshRate(layers, {.touch = true})); - - explicitExactOrMultipleLayer.desiredRefreshRate = 120_Hz; - explicitExactLayer.desiredRefreshRate = 60_Hz; - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); - - explicitExactLayer.desiredRefreshRate = 72_Hz; - EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers)); - - explicitExactLayer.desiredRefreshRate = 90_Hz; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - explicitExactLayer.desiredRefreshRate = 120_Hz; - EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers)); -} - -TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExactEnableFrameRateOverride) { - TestableRefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId60, - {.enableFrameRateOverride = true}); - - std::vector layers = {{.weight = 1.f}, {.weight = 0.5f}}; - auto& explicitExactLayer = layers[0]; - auto& explicitExactOrMultipleLayer = layers[1]; - - explicitExactOrMultipleLayer.vote = LayerVoteType::ExplicitExactOrMultiple; - explicitExactOrMultipleLayer.name = "ExplicitExactOrMultiple"; - explicitExactOrMultipleLayer.desiredRefreshRate = 60_Hz; - - explicitExactLayer.vote = LayerVoteType::ExplicitExact; - explicitExactLayer.name = "ExplicitExact"; - explicitExactLayer.desiredRefreshRate = 30_Hz; - - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); - EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers, {.touch = true})); - - explicitExactOrMultipleLayer.desiredRefreshRate = 120_Hz; - explicitExactLayer.desiredRefreshRate = 60_Hz; - EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers)); - - explicitExactLayer.desiredRefreshRate = 72_Hz; - EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers)); - - explicitExactLayer.desiredRefreshRate = 90_Hz; - EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); - - explicitExactLayer.desiredRefreshRate = 120_Hz; - EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers)); -} - -TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ReadsCache) { - TestableRefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId60); - - using GlobalSignals = RefreshRateConfigs::GlobalSignals; - const auto args = std::make_pair(std::vector{}, - GlobalSignals{.touch = true, .idle = true}); - - const RefreshRateConfigs::RankedRefreshRates result = {{RefreshRateConfigs::ScoredRefreshRate{ - kMode90}}, - {.touch = true}}; - - configs.mutableGetRankedRefreshRatesCache() = {args, result}; - - EXPECT_EQ(result, configs.getRankedRefreshRates(args.first, args.second)); -} - -TEST_F(RefreshRateConfigsTest, getBestRefreshRate_WritesCache) { - TestableRefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId60); - - EXPECT_FALSE(configs.mutableGetRankedRefreshRatesCache()); - - std::vector layers = {{.weight = 1.f}, {.weight = 0.5f}}; - RefreshRateConfigs::GlobalSignals globalSignals{.touch = true, .idle = true}; - - const auto result = configs.getRankedRefreshRates(layers, globalSignals); - - const auto& cache = configs.mutableGetRankedRefreshRatesCache(); - ASSERT_TRUE(cache); - - EXPECT_EQ(cache->arguments, std::make_pair(layers, globalSignals)); - EXPECT_EQ(cache->result, result); -} - -TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExactTouchBoost) { - TestableRefreshRateConfigs configs(kModes_60_120, kModeId60, {.enableFrameRateOverride = true}); - - std::vector layers = {{.weight = 1.f}, {.weight = 0.5f}}; - auto& explicitExactLayer = layers[0]; - auto& explicitExactOrMultipleLayer = layers[1]; - - explicitExactOrMultipleLayer.vote = LayerVoteType::ExplicitExactOrMultiple; - explicitExactOrMultipleLayer.name = "ExplicitExactOrMultiple"; - explicitExactOrMultipleLayer.desiredRefreshRate = 60_Hz; - - explicitExactLayer.vote = LayerVoteType::ExplicitExact; - explicitExactLayer.name = "ExplicitExact"; - explicitExactLayer.desiredRefreshRate = 30_Hz; - - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); - EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers, {.touch = true})); - - explicitExactOrMultipleLayer.vote = LayerVoteType::NoVote; - - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers, {.touch = true})); -} - -TEST_F(RefreshRateConfigsTest, getBestRefreshRate_FractionalRefreshRates_ExactAndDefault) { - TestableRefreshRateConfigs configs(kModes_24_25_30_50_60_Frac, kModeId60, - {.enableFrameRateOverride = true}); - - std::vector layers = {{.weight = 0.5f}, {.weight = 0.5f}}; - auto& explicitDefaultLayer = layers[0]; - auto& explicitExactOrMultipleLayer = layers[1]; - - explicitExactOrMultipleLayer.vote = LayerVoteType::ExplicitExactOrMultiple; - explicitExactOrMultipleLayer.name = "ExplicitExactOrMultiple"; - explicitExactOrMultipleLayer.desiredRefreshRate = 60_Hz; - - explicitDefaultLayer.vote = LayerVoteType::ExplicitDefault; - explicitDefaultLayer.name = "ExplicitDefault"; - explicitDefaultLayer.desiredRefreshRate = 59.94_Hz; - - EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); -} - -// b/190578904 -TEST_F(RefreshRateConfigsTest, getBestRefreshRate_withCloseRefreshRates) { - constexpr int kMinRefreshRate = 10; - constexpr int kMaxRefreshRate = 240; - - DisplayModes displayModes; - for (int fps = kMinRefreshRate; fps < kMaxRefreshRate; fps++) { - const DisplayModeId modeId(fps); - displayModes.try_emplace(modeId, - createDisplayMode(modeId, - Fps::fromValue(static_cast(fps)))); - } - - const TestableRefreshRateConfigs configs(std::move(displayModes), - DisplayModeId(kMinRefreshRate)); - - std::vector layers = {{.weight = 1.f}}; - const auto testRefreshRate = [&](Fps fps, LayerVoteType vote) { - layers[0].desiredRefreshRate = fps; - layers[0].vote = vote; - EXPECT_EQ(fps.getIntValue(), configs.getBestRefreshRate(layers)->getFps().getIntValue()) - << "Failed for " << ftl::enum_string(vote); - }; - - for (int fps = kMinRefreshRate; fps < kMaxRefreshRate; fps++) { - const auto refreshRate = Fps::fromValue(static_cast(fps)); - testRefreshRate(refreshRate, LayerVoteType::Heuristic); - testRefreshRate(refreshRate, LayerVoteType::ExplicitDefault); - testRefreshRate(refreshRate, LayerVoteType::ExplicitExactOrMultiple); - testRefreshRate(refreshRate, LayerVoteType::ExplicitExact); - } -} - -// b/190578904 -TEST_F(RefreshRateConfigsTest, getBestRefreshRate_conflictingVotes) { - constexpr DisplayModeId kActiveModeId{0}; - DisplayModes displayModes = makeModes(createDisplayMode(kActiveModeId, 43_Hz), - createDisplayMode(DisplayModeId(1), 53_Hz), - createDisplayMode(DisplayModeId(2), 55_Hz), - createDisplayMode(DisplayModeId(3), 60_Hz)); - - const RefreshRateConfigs::GlobalSignals globalSignals = {.touch = false, .idle = false}; - const TestableRefreshRateConfigs configs(std::move(displayModes), kActiveModeId); - - const std::vector layers = { - { - .vote = LayerVoteType::ExplicitDefault, - .desiredRefreshRate = 43_Hz, - .seamlessness = Seamlessness::SeamedAndSeamless, - .weight = 0.41f, - }, - { - .vote = LayerVoteType::ExplicitExactOrMultiple, - .desiredRefreshRate = 53_Hz, - .seamlessness = Seamlessness::SeamedAndSeamless, - .weight = 0.41f, - }, - }; - - EXPECT_EQ(53_Hz, configs.getBestRefreshRate(layers, globalSignals)->getFps()); -} - -TEST_F(RefreshRateConfigsTest, modeComparison) { - EXPECT_LT(kMode60->getFps(), kMode90->getFps()); - EXPECT_GE(kMode60->getFps(), kMode60->getFps()); - EXPECT_GE(kMode90->getFps(), kMode90->getFps()); -} - -TEST_F(RefreshRateConfigsTest, testKernelIdleTimerAction) { - using KernelIdleTimerAction = RefreshRateConfigs::KernelIdleTimerAction; - - TestableRefreshRateConfigs configs(kModes_60_90, kModeId90); - - // setPolicy(60, 90), current 90Hz => TurnOn. - EXPECT_EQ(KernelIdleTimerAction::TurnOn, configs.getIdleTimerAction()); - - // setPolicy(60, 90), current 60Hz => TurnOn. - EXPECT_EQ(SetPolicyResult::Changed, - configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 90_Hz}})); - EXPECT_EQ(KernelIdleTimerAction::TurnOn, configs.getIdleTimerAction()); - - // setPolicy(60, 60), current 60Hz => TurnOff - EXPECT_EQ(SetPolicyResult::Changed, - configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}})); - EXPECT_EQ(KernelIdleTimerAction::TurnOff, configs.getIdleTimerAction()); - - // setPolicy(90, 90), current 90Hz => TurnOff. - EXPECT_EQ(SetPolicyResult::Changed, - configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}})); - EXPECT_EQ(KernelIdleTimerAction::TurnOff, configs.getIdleTimerAction()); -} - -TEST_F(RefreshRateConfigsTest, testKernelIdleTimerActionFor120Hz) { - using KernelIdleTimerAction = RefreshRateConfigs::KernelIdleTimerAction; - - TestableRefreshRateConfigs configs(kModes_60_120, kModeId120); - - // setPolicy(0, 60), current 60Hz => TurnOn. - EXPECT_EQ(SetPolicyResult::Changed, - configs.setDisplayManagerPolicy({kModeId60, {0_Hz, 60_Hz}})); - EXPECT_EQ(KernelIdleTimerAction::TurnOn, configs.getIdleTimerAction()); - - // setPolicy(60, 60), current 60Hz => TurnOff. - EXPECT_EQ(SetPolicyResult::Changed, - configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}})); - EXPECT_EQ(KernelIdleTimerAction::TurnOff, configs.getIdleTimerAction()); - - // setPolicy(60, 120), current 60Hz => TurnOn. - EXPECT_EQ(SetPolicyResult::Changed, - configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 120_Hz}})); - EXPECT_EQ(KernelIdleTimerAction::TurnOn, configs.getIdleTimerAction()); - - // setPolicy(120, 120), current 120Hz => TurnOff. - EXPECT_EQ(SetPolicyResult::Changed, - configs.setDisplayManagerPolicy({kModeId120, {120_Hz, 120_Hz}})); - EXPECT_EQ(KernelIdleTimerAction::TurnOff, configs.getIdleTimerAction()); -} - -TEST_F(RefreshRateConfigsTest, getFrameRateDivisor) { - TestableRefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId30); - - const auto frameRate = 30_Hz; - Fps displayRefreshRate = configs.getActiveMode().getFps(); - EXPECT_EQ(1, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate)); - - configs.setActiveModeId(kModeId60); - displayRefreshRate = configs.getActiveMode().getFps(); - EXPECT_EQ(2, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate)); - - configs.setActiveModeId(kModeId72); - displayRefreshRate = configs.getActiveMode().getFps(); - EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate)); - - configs.setActiveModeId(kModeId90); - displayRefreshRate = configs.getActiveMode().getFps(); - EXPECT_EQ(3, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate)); - - configs.setActiveModeId(kModeId120); - displayRefreshRate = configs.getActiveMode().getFps(); - EXPECT_EQ(4, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate)); - - configs.setActiveModeId(kModeId90); - displayRefreshRate = configs.getActiveMode().getFps(); - EXPECT_EQ(4, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, 22.5_Hz)); - - EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivisor(24_Hz, 25_Hz)); - EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivisor(24_Hz, 23.976_Hz)); - EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivisor(30_Hz, 29.97_Hz)); - EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivisor(60_Hz, 59.94_Hz)); -} - -TEST_F(RefreshRateConfigsTest, isFractionalPairOrMultiple) { - EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(23.976_Hz, 24_Hz)); - EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(24_Hz, 23.976_Hz)); - - EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(29.97_Hz, 30_Hz)); - EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(30_Hz, 29.97_Hz)); - - EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(59.94_Hz, 60_Hz)); - EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(60_Hz, 59.94_Hz)); - - EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(29.97_Hz, 60_Hz)); - EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(60_Hz, 29.97_Hz)); - - EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(59.94_Hz, 30_Hz)); - EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(30_Hz, 59.94_Hz)); - - const auto refreshRates = {23.976_Hz, 24_Hz, 25_Hz, 29.97_Hz, 30_Hz, 50_Hz, 59.94_Hz, 60_Hz}; - for (auto refreshRate : refreshRates) { - EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(refreshRate, refreshRate)); - } - - EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(24_Hz, 25_Hz)); - EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(23.978_Hz, 25_Hz)); - EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(29.97_Hz, 59.94_Hz)); -} - -TEST_F(RefreshRateConfigsTest, getFrameRateOverrides_noLayers) { - RefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId120); - - EXPECT_TRUE(configs.getFrameRateOverrides({}, 120_Hz, {}).empty()); -} - -TEST_F(RefreshRateConfigsTest, getFrameRateOverrides_60on120) { - RefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId120, - {.enableFrameRateOverride = true}); - - std::vector layers = {{.weight = 1.f}}; - layers[0].name = "Test layer"; - layers[0].ownerUid = 1234; - layers[0].desiredRefreshRate = 60_Hz; - layers[0].vote = LayerVoteType::ExplicitDefault; - - auto frameRateOverrides = configs.getFrameRateOverrides(layers, 120_Hz, {}); - EXPECT_EQ(1u, frameRateOverrides.size()); - ASSERT_EQ(1u, frameRateOverrides.count(1234)); - EXPECT_EQ(60_Hz, frameRateOverrides.at(1234)); - - layers[0].vote = LayerVoteType::ExplicitExactOrMultiple; - frameRateOverrides = configs.getFrameRateOverrides(layers, 120_Hz, {}); - EXPECT_EQ(1u, frameRateOverrides.size()); - ASSERT_EQ(1u, frameRateOverrides.count(1234)); - EXPECT_EQ(60_Hz, frameRateOverrides.at(1234)); - - layers[0].vote = LayerVoteType::NoVote; - frameRateOverrides = configs.getFrameRateOverrides(layers, 120_Hz, {}); - EXPECT_TRUE(frameRateOverrides.empty()); - - layers[0].vote = LayerVoteType::Min; - frameRateOverrides = configs.getFrameRateOverrides(layers, 120_Hz, {}); - EXPECT_TRUE(frameRateOverrides.empty()); - - layers[0].vote = LayerVoteType::Max; - frameRateOverrides = configs.getFrameRateOverrides(layers, 120_Hz, {}); - EXPECT_TRUE(frameRateOverrides.empty()); - - layers[0].vote = LayerVoteType::Heuristic; - frameRateOverrides = configs.getFrameRateOverrides(layers, 120_Hz, {}); - EXPECT_TRUE(frameRateOverrides.empty()); -} - -TEST_F(RefreshRateConfigsTest, getFrameRateOverrides_twoUids) { - RefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId120, - {.enableFrameRateOverride = true}); - - std::vector layers = {{.ownerUid = 1234, .weight = 1.f}, - {.ownerUid = 5678, .weight = 1.f}}; - - layers[0].name = "Test layer 1234"; - layers[0].desiredRefreshRate = 60_Hz; - layers[0].vote = LayerVoteType::ExplicitDefault; - - layers[1].name = "Test layer 5678"; - layers[1].desiredRefreshRate = 30_Hz; - layers[1].vote = LayerVoteType::ExplicitDefault; - auto frameRateOverrides = configs.getFrameRateOverrides(layers, 120_Hz, {}); - - EXPECT_EQ(2u, frameRateOverrides.size()); - ASSERT_EQ(1u, frameRateOverrides.count(1234)); - EXPECT_EQ(60_Hz, frameRateOverrides.at(1234)); - ASSERT_EQ(1u, frameRateOverrides.count(5678)); - EXPECT_EQ(30_Hz, frameRateOverrides.at(5678)); - - layers[1].vote = LayerVoteType::Heuristic; - frameRateOverrides = configs.getFrameRateOverrides(layers, 120_Hz, {}); - EXPECT_EQ(1u, frameRateOverrides.size()); - ASSERT_EQ(1u, frameRateOverrides.count(1234)); - EXPECT_EQ(60_Hz, frameRateOverrides.at(1234)); - - layers[1].ownerUid = 1234; - frameRateOverrides = configs.getFrameRateOverrides(layers, 120_Hz, {}); - EXPECT_TRUE(frameRateOverrides.empty()); -} - -TEST_F(RefreshRateConfigsTest, getFrameRateOverrides_touch) { - RefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId120, - {.enableFrameRateOverride = true}); - - std::vector layers = {{.ownerUid = 1234, .weight = 1.f}}; - layers[0].name = "Test layer"; - layers[0].desiredRefreshRate = 60_Hz; - layers[0].vote = LayerVoteType::ExplicitDefault; - - auto frameRateOverrides = configs.getFrameRateOverrides(layers, 120_Hz, {}); - EXPECT_EQ(1u, frameRateOverrides.size()); - ASSERT_EQ(1u, frameRateOverrides.count(1234)); - EXPECT_EQ(60_Hz, frameRateOverrides.at(1234)); - - frameRateOverrides = configs.getFrameRateOverrides(layers, 120_Hz, {.touch = true}); - EXPECT_EQ(1u, frameRateOverrides.size()); - ASSERT_EQ(1u, frameRateOverrides.count(1234)); - EXPECT_EQ(60_Hz, frameRateOverrides.at(1234)); - - layers[0].vote = LayerVoteType::ExplicitExact; - frameRateOverrides = configs.getFrameRateOverrides(layers, 120_Hz, {}); - EXPECT_EQ(1u, frameRateOverrides.size()); - ASSERT_EQ(1u, frameRateOverrides.count(1234)); - EXPECT_EQ(60_Hz, frameRateOverrides.at(1234)); - - frameRateOverrides = configs.getFrameRateOverrides(layers, 120_Hz, {.touch = true}); - EXPECT_EQ(1u, frameRateOverrides.size()); - ASSERT_EQ(1u, frameRateOverrides.count(1234)); - EXPECT_EQ(60_Hz, frameRateOverrides.at(1234)); - - layers[0].vote = LayerVoteType::ExplicitExactOrMultiple; - frameRateOverrides = configs.getFrameRateOverrides(layers, 120_Hz, {}); - EXPECT_EQ(1u, frameRateOverrides.size()); - ASSERT_EQ(1u, frameRateOverrides.count(1234)); - EXPECT_EQ(60_Hz, frameRateOverrides.at(1234)); - - frameRateOverrides = configs.getFrameRateOverrides(layers, 120_Hz, {.touch = true}); - EXPECT_TRUE(frameRateOverrides.empty()); -} - -} // namespace -} // namespace android::scheduler diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp new file mode 100644 index 0000000000..e7ae53c01a --- /dev/null +++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp @@ -0,0 +1,2421 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#undef LOG_TAG +#define LOG_TAG "SchedulerUnittests" + +#include +#include + +#include +#include +#include +#include +#include + +#include "DisplayHardware/HWC2.h" +#include "FpsOps.h" +#include "Scheduler/RefreshRateSelector.h" +#include "mock/DisplayHardware/MockDisplayMode.h" + +using namespace std::chrono_literals; + +namespace android::scheduler { + +namespace hal = android::hardware::graphics::composer::hal; + +using LayerRequirement = RefreshRateSelector::LayerRequirement; +using LayerVoteType = RefreshRateSelector::LayerVoteType; +using SetPolicyResult = RefreshRateSelector::SetPolicyResult; + +using mock::createDisplayMode; + +struct TestableRefreshRateSelector : RefreshRateSelector { + using RefreshRateSelector::RefreshRateOrder; + using RefreshRateSelector::RefreshRateRanking; + + using RefreshRateSelector::RefreshRateSelector; + + void setActiveModeId(DisplayModeId modeId) { + ftl::FakeGuard guard(kMainThreadContext); + return RefreshRateSelector::setActiveModeId(modeId); + } + + const DisplayMode& getActiveMode() const { + ftl::FakeGuard guard(kMainThreadContext); + return RefreshRateSelector::getActiveMode(); + } + + DisplayModePtr getMinSupportedRefreshRate() const { + std::lock_guard lock(mLock); + return mMinRefreshRateModeIt->second; + } + + DisplayModePtr getMaxSupportedRefreshRate() const { + std::lock_guard lock(mLock); + return mMaxRefreshRateModeIt->second; + } + + DisplayModePtr getMinRefreshRateByPolicy() const { + std::lock_guard lock(mLock); + return getMinRefreshRateByPolicyLocked(); + } + + DisplayModePtr getMaxRefreshRateByPolicy() const { + std::lock_guard lock(mLock); + return getMaxRefreshRateByPolicyLocked(getActiveModeItLocked()->second->getGroup()); + } + + RefreshRateRanking rankRefreshRates(std::optional anchorGroupOpt, + RefreshRateOrder refreshRateOrder) const { + std::lock_guard lock(mLock); + return RefreshRateSelector::rankRefreshRates(anchorGroupOpt, refreshRateOrder); + } + + const std::vector& knownFrameRates() const { return mKnownFrameRates; } + + using RefreshRateSelector::GetRankedRefreshRatesCache; + auto& mutableGetRankedRefreshRatesCache() { return mGetRankedRefreshRatesCache; } + + auto getRankedRefreshRates(const std::vector& layers, + GlobalSignals signals) const { + const auto result = RefreshRateSelector::getRankedRefreshRates(layers, signals); + + EXPECT_TRUE(std::is_sorted(result.ranking.begin(), result.ranking.end(), + ScoredRefreshRate::DescendingScore{})); + + return result; + } + + auto getRankedRefreshRatesAsPair(const std::vector& layers, + GlobalSignals signals) const { + const auto [ranking, consideredSignals] = getRankedRefreshRates(layers, signals); + return std::make_pair(ranking, consideredSignals); + } + + DisplayModePtr getBestRefreshRate(const std::vector& layers = {}, + GlobalSignals signals = {}) const { + return getRankedRefreshRates(layers, signals).ranking.front().modePtr; + } + + SetPolicyResult setPolicy(const PolicyVariant& policy) { + ftl::FakeGuard guard(kMainThreadContext); + return RefreshRateSelector::setPolicy(policy); + } + + SetPolicyResult setDisplayManagerPolicy(const DisplayManagerPolicy& policy) { + return setPolicy(policy); + } +}; + +class RefreshRateSelectorTest : public testing::Test { +protected: + using RefreshRateOrder = TestableRefreshRateSelector::RefreshRateOrder; + + RefreshRateSelectorTest(); + ~RefreshRateSelectorTest(); + + static constexpr DisplayModeId kModeId60{0}; + static constexpr DisplayModeId kModeId90{1}; + static constexpr DisplayModeId kModeId72{2}; + static constexpr DisplayModeId kModeId120{3}; + static constexpr DisplayModeId kModeId30{4}; + static constexpr DisplayModeId kModeId25{5}; + static constexpr DisplayModeId kModeId50{6}; + static constexpr DisplayModeId kModeId24{7}; + static constexpr DisplayModeId kModeId24Frac{8}; + static constexpr DisplayModeId kModeId30Frac{9}; + static constexpr DisplayModeId kModeId60Frac{10}; + + static inline const DisplayModePtr kMode60 = createDisplayMode(kModeId60, 60_Hz); + static inline const DisplayModePtr kMode60Frac = createDisplayMode(kModeId60Frac, 59.94_Hz); + static inline const DisplayModePtr kMode90 = createDisplayMode(kModeId90, 90_Hz); + static inline const DisplayModePtr kMode90_G1 = createDisplayMode(kModeId90, 90_Hz, 1); + static inline const DisplayModePtr kMode90_4K = + createDisplayMode(kModeId90, 90_Hz, 0, {3840, 2160}); + static inline const DisplayModePtr kMode72 = createDisplayMode(kModeId72, 72_Hz); + static inline const DisplayModePtr kMode72_G1 = createDisplayMode(kModeId72, 72_Hz, 1); + static inline const DisplayModePtr kMode120 = createDisplayMode(kModeId120, 120_Hz); + static inline const DisplayModePtr kMode120_G1 = createDisplayMode(kModeId120, 120_Hz, 1); + static inline const DisplayModePtr kMode30 = createDisplayMode(kModeId30, 30_Hz); + static inline const DisplayModePtr kMode30_G1 = createDisplayMode(kModeId30, 30_Hz, 1); + static inline const DisplayModePtr kMode30Frac = createDisplayMode(kModeId30Frac, 29.97_Hz); + static inline const DisplayModePtr kMode25 = createDisplayMode(kModeId25, 25_Hz); + static inline const DisplayModePtr kMode25_G1 = createDisplayMode(kModeId25, 25_Hz, 1); + static inline const DisplayModePtr kMode50 = createDisplayMode(kModeId50, 50_Hz); + static inline const DisplayModePtr kMode24 = createDisplayMode(kModeId24, 24_Hz); + static inline const DisplayModePtr kMode24Frac = createDisplayMode(kModeId24Frac, 23.976_Hz); + + // Test configurations. + static inline const DisplayModes kModes_60 = makeModes(kMode60); + static inline const DisplayModes kModes_60_90 = makeModes(kMode60, kMode90); + static inline const DisplayModes kModes_60_90_G1 = makeModes(kMode60, kMode90_G1); + static inline const DisplayModes kModes_60_90_4K = makeModes(kMode60, kMode90_4K); + static inline const DisplayModes kModes_60_72_90 = makeModes(kMode60, kMode90, kMode72); + static inline const DisplayModes kModes_60_90_72_120 = + makeModes(kMode60, kMode90, kMode72, kMode120); + static inline const DisplayModes kModes_30_60_72_90_120 = + makeModes(kMode60, kMode90, kMode72, kMode120, kMode30); + + static inline const DisplayModes kModes_30_60 = + makeModes(kMode60, kMode90_G1, kMode72_G1, kMode120_G1, kMode30); + static inline const DisplayModes kModes_30_60_72_90 = + makeModes(kMode60, kMode90, kMode72, kMode120_G1, kMode30); + static inline const DisplayModes kModes_30_60_90 = + makeModes(kMode60, kMode90, kMode72_G1, kMode120_G1, kMode30); + static inline const DisplayModes kModes_25_30_50_60 = + makeModes(kMode60, kMode90, kMode72_G1, kMode120_G1, kMode30_G1, kMode25_G1, kMode50); + static inline const DisplayModes kModes_60_120 = makeModes(kMode60, kMode120); + + // This is a typical TV configuration. + static inline const DisplayModes kModes_24_25_30_50_60_Frac = + makeModes(kMode24, kMode24Frac, kMode25, kMode30, kMode30Frac, kMode50, kMode60, + kMode60Frac); +}; + +RefreshRateSelectorTest::RefreshRateSelectorTest() { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); +} + +RefreshRateSelectorTest::~RefreshRateSelectorTest() { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); +} + +namespace { + +TEST_F(RefreshRateSelectorTest, oneMode_canSwitch) { + RefreshRateSelector selector(kModes_60, kModeId60); + EXPECT_FALSE(selector.canSwitch()); +} + +TEST_F(RefreshRateSelectorTest, invalidPolicy) { + TestableRefreshRateSelector selector(kModes_60, kModeId60); + + EXPECT_EQ(SetPolicyResult::Invalid, + selector.setDisplayManagerPolicy({DisplayModeId(10), {60_Hz, 60_Hz}})); + EXPECT_EQ(SetPolicyResult::Invalid, + selector.setDisplayManagerPolicy({kModeId60, {20_Hz, 40_Hz}})); +} + +TEST_F(RefreshRateSelectorTest, unchangedPolicy) { + TestableRefreshRateSelector selector(kModes_60_90, kModeId60); + + EXPECT_EQ(SetPolicyResult::Changed, + selector.setDisplayManagerPolicy({kModeId90, {60_Hz, 90_Hz}})); + + EXPECT_EQ(SetPolicyResult::Unchanged, + selector.setDisplayManagerPolicy({kModeId90, {60_Hz, 90_Hz}})); + + // Override to the same policy. + EXPECT_EQ(SetPolicyResult::Unchanged, + selector.setPolicy(RefreshRateSelector::OverridePolicy{kModeId90, {60_Hz, 90_Hz}})); + + // Clear override to restore DisplayManagerPolicy. + EXPECT_EQ(SetPolicyResult::Unchanged, + selector.setPolicy(RefreshRateSelector::NoOverridePolicy{})); + + EXPECT_EQ(SetPolicyResult::Changed, + selector.setDisplayManagerPolicy({kModeId90, {30_Hz, 90_Hz}})); +} + +TEST_F(RefreshRateSelectorTest, twoModes_storesFullRefreshRateMap) { + TestableRefreshRateSelector selector(kModes_60_90, kModeId60); + + const auto minRate = selector.getMinSupportedRefreshRate(); + const auto performanceRate = selector.getMaxSupportedRefreshRate(); + + EXPECT_EQ(kMode60, minRate); + EXPECT_EQ(kMode90, performanceRate); + + const auto minRateByPolicy = selector.getMinRefreshRateByPolicy(); + const auto performanceRateByPolicy = selector.getMaxRefreshRateByPolicy(); + + EXPECT_EQ(minRateByPolicy, minRate); + EXPECT_EQ(performanceRateByPolicy, performanceRate); +} + +TEST_F(RefreshRateSelectorTest, twoModes_storesFullRefreshRateMap_differentGroups) { + TestableRefreshRateSelector selector(kModes_60_90_G1, kModeId60); + + const auto minRate = selector.getMinRefreshRateByPolicy(); + const auto performanceRate = selector.getMaxSupportedRefreshRate(); + const auto minRate60 = selector.getMinRefreshRateByPolicy(); + const auto performanceRate60 = selector.getMaxRefreshRateByPolicy(); + + EXPECT_EQ(kMode60, minRate); + EXPECT_EQ(kMode60, minRate60); + EXPECT_EQ(kMode60, performanceRate60); + + EXPECT_EQ(SetPolicyResult::Changed, + selector.setDisplayManagerPolicy({kModeId90, {60_Hz, 90_Hz}})); + selector.setActiveModeId(kModeId90); + + const auto minRate90 = selector.getMinRefreshRateByPolicy(); + const auto performanceRate90 = selector.getMaxRefreshRateByPolicy(); + + EXPECT_EQ(kMode90_G1, performanceRate); + EXPECT_EQ(kMode90_G1, minRate90); + EXPECT_EQ(kMode90_G1, performanceRate90); +} + +TEST_F(RefreshRateSelectorTest, twoModes_storesFullRefreshRateMap_differentResolutions) { + TestableRefreshRateSelector selector(kModes_60_90_4K, kModeId60); + + const auto minRate = selector.getMinRefreshRateByPolicy(); + const auto performanceRate = selector.getMaxSupportedRefreshRate(); + const auto minRate60 = selector.getMinRefreshRateByPolicy(); + const auto performanceRate60 = selector.getMaxRefreshRateByPolicy(); + + EXPECT_EQ(kMode60, minRate); + EXPECT_EQ(kMode60, minRate60); + EXPECT_EQ(kMode60, performanceRate60); + + EXPECT_EQ(SetPolicyResult::Changed, + selector.setDisplayManagerPolicy({kModeId90, {60_Hz, 90_Hz}})); + selector.setActiveModeId(kModeId90); + + const auto minRate90 = selector.getMinRefreshRateByPolicy(); + const auto performanceRate90 = selector.getMaxRefreshRateByPolicy(); + + EXPECT_EQ(kMode90_4K, performanceRate); + EXPECT_EQ(kMode90_4K, minRate90); + EXPECT_EQ(kMode90_4K, performanceRate90); +} + +TEST_F(RefreshRateSelectorTest, twoModes_policyChange) { + TestableRefreshRateSelector selector(kModes_60_90, kModeId60); + + const auto minRate = selector.getMinRefreshRateByPolicy(); + const auto performanceRate = selector.getMaxRefreshRateByPolicy(); + + EXPECT_EQ(kMode60, minRate); + EXPECT_EQ(kMode90, performanceRate); + + EXPECT_EQ(SetPolicyResult::Changed, + selector.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}})); + + const auto minRate60 = selector.getMinRefreshRateByPolicy(); + const auto performanceRate60 = selector.getMaxRefreshRateByPolicy(); + + EXPECT_EQ(kMode60, minRate60); + EXPECT_EQ(kMode60, performanceRate60); +} + +TEST_F(RefreshRateSelectorTest, twoModes_getActiveMode) { + TestableRefreshRateSelector selector(kModes_60_90, kModeId60); + { + const auto& mode = selector.getActiveMode(); + EXPECT_EQ(mode.getId(), kModeId60); + } + + selector.setActiveModeId(kModeId90); + { + const auto& mode = selector.getActiveMode(); + EXPECT_EQ(mode.getId(), kModeId90); + } + + EXPECT_EQ(SetPolicyResult::Changed, + selector.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}})); + { + const auto& mode = selector.getActiveMode(); + EXPECT_EQ(mode.getId(), kModeId90); + } +} + +TEST_F(RefreshRateSelectorTest, getBestRefreshRate_noLayers) { + { + TestableRefreshRateSelector selector(kModes_60_72_90, kModeId72); + + // If there are no layers we select the default frame rate, which is the max of the primary + // range. + EXPECT_EQ(kMode90, selector.getBestRefreshRate()); + + EXPECT_EQ(SetPolicyResult::Changed, + selector.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}})); + EXPECT_EQ(kMode60, selector.getBestRefreshRate()); + } + { + // We select max even when this will cause a non-seamless switch. + TestableRefreshRateSelector selector(kModes_60_90_G1, kModeId60); + constexpr bool kAllowGroupSwitching = true; + EXPECT_EQ(SetPolicyResult::Changed, + selector.setDisplayManagerPolicy( + {kModeId90, kAllowGroupSwitching, {0_Hz, 90_Hz}})); + EXPECT_EQ(kMode90_G1, selector.getBestRefreshRate()); + } +} + +TEST_F(RefreshRateSelectorTest, getBestRefreshRate_exactDontChangeRefreshRateWhenNotInPolicy) { + TestableRefreshRateSelector selector(kModes_30_60_72_90_120, kModeId72); + + std::vector layers = {{.weight = 1.f}}; + layers[0].vote = LayerVoteType::ExplicitExact; + layers[0].desiredRefreshRate = 120_Hz; + + EXPECT_EQ(SetPolicyResult::Changed, + selector.setDisplayManagerPolicy({kModeId72, {0_Hz, 90_Hz}})); + EXPECT_EQ(kMode72, selector.getBestRefreshRate(layers)); +} + +TEST_F(RefreshRateSelectorTest, getBestRefreshRate_60_90) { + TestableRefreshRateSelector selector(kModes_60_90, kModeId60); + + std::vector layers = {{.weight = 1.f}}; + auto& lr = layers[0]; + + lr.vote = LayerVoteType::Min; + lr.name = "Min"; + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); + + lr.vote = LayerVoteType::Max; + lr.name = "Max"; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 90_Hz; + lr.vote = LayerVoteType::Heuristic; + lr.name = "90Hz Heuristic"; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 60_Hz; + lr.name = "60Hz Heuristic"; + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 45_Hz; + lr.name = "45Hz Heuristic"; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 30_Hz; + lr.name = "30Hz Heuristic"; + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 24_Hz; + lr.name = "24Hz Heuristic"; + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); + + lr.name = ""; + EXPECT_EQ(SetPolicyResult::Changed, + selector.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}})); + + lr.vote = LayerVoteType::Min; + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); + + lr.vote = LayerVoteType::Max; + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 90_Hz; + lr.vote = LayerVoteType::Heuristic; + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 60_Hz; + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 45_Hz; + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 30_Hz; + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 24_Hz; + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); + + EXPECT_EQ(SetPolicyResult::Changed, + selector.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}})); + + lr.vote = LayerVoteType::Min; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr.vote = LayerVoteType::Max; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 90_Hz; + lr.vote = LayerVoteType::Heuristic; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 60_Hz; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 45_Hz; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 30_Hz; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 24_Hz; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + EXPECT_EQ(SetPolicyResult::Changed, + selector.setDisplayManagerPolicy({kModeId60, {0_Hz, 120_Hz}})); + lr.vote = LayerVoteType::Min; + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); + + lr.vote = LayerVoteType::Max; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 90_Hz; + lr.vote = LayerVoteType::Heuristic; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 60_Hz; + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 45_Hz; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 30_Hz; + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 24_Hz; + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); +} + +TEST_F(RefreshRateSelectorTest, getBestRefreshRate_multipleThreshold_60_90) { + TestableRefreshRateSelector selector(kModes_60_90, kModeId60, + {.frameRateMultipleThreshold = 90}); + + std::vector layers = {{.weight = 1.f}}; + auto& lr = layers[0]; + + lr.vote = LayerVoteType::Min; + lr.name = "Min"; + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); + + lr.vote = LayerVoteType::Max; + lr.name = "Max"; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 90_Hz; + lr.vote = LayerVoteType::Heuristic; + lr.name = "90Hz Heuristic"; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 60_Hz; + lr.name = "60Hz Heuristic"; + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 45_Hz; + lr.name = "45Hz Heuristic"; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 30_Hz; + lr.name = "30Hz Heuristic"; + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 24_Hz; + lr.name = "24Hz Heuristic"; + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); +} + +TEST_F(RefreshRateSelectorTest, getBestRefreshRate_60_72_90) { + TestableRefreshRateSelector selector(kModes_60_72_90, kModeId60); + + std::vector layers = {{.weight = 1.f}}; + auto& lr = layers[0]; + + lr.vote = LayerVoteType::Min; + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); + + lr.vote = LayerVoteType::Max; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 90_Hz; + lr.vote = LayerVoteType::Heuristic; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 60_Hz; + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 45_Hz; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 30_Hz; + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 24_Hz; + EXPECT_EQ(kMode72, selector.getBestRefreshRate(layers)); +} + +TEST_F(RefreshRateSelectorTest, getBestRefreshRate_30_60_72_90_120) { + TestableRefreshRateSelector selector(kModes_30_60_72_90_120, kModeId60); + + std::vector layers = {{.weight = 1.f}, {.weight = 1.f}}; + auto& lr1 = layers[0]; + auto& lr2 = layers[1]; + + lr1.desiredRefreshRate = 24_Hz; + lr1.vote = LayerVoteType::Heuristic; + lr2.desiredRefreshRate = 60_Hz; + lr2.vote = LayerVoteType::Heuristic; + EXPECT_EQ(kMode120, selector.getBestRefreshRate(layers)); + + lr1.desiredRefreshRate = 24_Hz; + lr1.vote = LayerVoteType::Heuristic; + lr2.desiredRefreshRate = 48_Hz; + lr2.vote = LayerVoteType::Heuristic; + EXPECT_EQ(kMode72, selector.getBestRefreshRate(layers)); + + lr1.desiredRefreshRate = 24_Hz; + lr1.vote = LayerVoteType::Heuristic; + lr2.desiredRefreshRate = 48_Hz; + lr2.vote = LayerVoteType::Heuristic; + EXPECT_EQ(kMode72, selector.getBestRefreshRate(layers)); +} + +TEST_F(RefreshRateSelectorTest, getBestRefreshRate_30_60_90_120_DifferentTypes) { + TestableRefreshRateSelector selector(kModes_30_60_72_90_120, kModeId60); + + std::vector layers = {{.weight = 1.f}, {.weight = 1.f}}; + auto& lr1 = layers[0]; + auto& lr2 = layers[1]; + + lr1.desiredRefreshRate = 24_Hz; + lr1.vote = LayerVoteType::ExplicitDefault; + lr1.name = "24Hz ExplicitDefault"; + lr2.desiredRefreshRate = 60_Hz; + lr2.vote = LayerVoteType::Heuristic; + lr2.name = "60Hz Heuristic"; + EXPECT_EQ(kMode120, selector.getBestRefreshRate(layers)); + + lr1.desiredRefreshRate = 24_Hz; + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.name = "24Hz ExplicitExactOrMultiple"; + lr2.desiredRefreshRate = 60_Hz; + lr2.vote = LayerVoteType::Heuristic; + lr2.name = "60Hz Heuristic"; + EXPECT_EQ(kMode120, selector.getBestRefreshRate(layers)); + + lr1.desiredRefreshRate = 24_Hz; + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.name = "24Hz ExplicitExactOrMultiple"; + lr2.desiredRefreshRate = 60_Hz; + lr2.vote = LayerVoteType::ExplicitDefault; + lr2.name = "60Hz ExplicitDefault"; + EXPECT_EQ(kMode120, selector.getBestRefreshRate(layers)); + + lr1.desiredRefreshRate = 24_Hz; + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.name = "24Hz ExplicitExactOrMultiple"; + lr2.desiredRefreshRate = 90_Hz; + lr2.vote = LayerVoteType::Heuristic; + lr2.name = "90Hz Heuristic"; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr1.desiredRefreshRate = 24_Hz; + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.name = "24Hz ExplicitExactOrMultiple"; + lr2.desiredRefreshRate = 90_Hz; + lr2.vote = LayerVoteType::ExplicitDefault; + lr2.name = "90Hz Heuristic"; + EXPECT_EQ(kMode72, selector.getBestRefreshRate(layers)); + + lr1.desiredRefreshRate = 24_Hz; + lr1.vote = LayerVoteType::ExplicitDefault; + lr1.name = "24Hz ExplicitDefault"; + lr2.desiredRefreshRate = 90_Hz; + lr2.vote = LayerVoteType::Heuristic; + lr2.name = "90Hz Heuristic"; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr1.desiredRefreshRate = 24_Hz; + lr1.vote = LayerVoteType::Heuristic; + lr1.name = "24Hz Heuristic"; + lr2.desiredRefreshRate = 90_Hz; + lr2.vote = LayerVoteType::ExplicitDefault; + lr2.name = "90Hz ExplicitDefault"; + EXPECT_EQ(kMode72, selector.getBestRefreshRate(layers)); + + lr1.desiredRefreshRate = 24_Hz; + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.name = "24Hz ExplicitExactOrMultiple"; + lr2.desiredRefreshRate = 90_Hz; + lr2.vote = LayerVoteType::ExplicitDefault; + lr2.name = "90Hz ExplicitDefault"; + EXPECT_EQ(kMode72, selector.getBestRefreshRate(layers)); + + lr1.desiredRefreshRate = 24_Hz; + lr1.vote = LayerVoteType::ExplicitDefault; + lr1.name = "24Hz ExplicitDefault"; + lr2.desiredRefreshRate = 90_Hz; + lr2.vote = LayerVoteType::ExplicitExactOrMultiple; + lr2.name = "90Hz ExplicitExactOrMultiple"; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); +} + +TEST_F(RefreshRateSelectorTest, getBestRefreshRate_30_60_90_120_DifferentTypes_multipleThreshold) { + TestableRefreshRateSelector selector(kModes_30_60_72_90_120, kModeId60, + {.frameRateMultipleThreshold = 120}); + + std::vector layers = {{.weight = 1.f}, {.weight = 1.f}, {.weight = 1.f}}; + auto& lr1 = layers[0]; + auto& lr2 = layers[1]; + auto& lr3 = layers[2]; + + lr1.desiredRefreshRate = 24_Hz; + lr1.vote = LayerVoteType::ExplicitDefault; + lr1.name = "24Hz ExplicitDefault"; + lr2.desiredRefreshRate = 60_Hz; + lr2.vote = LayerVoteType::Heuristic; + lr2.name = "60Hz Heuristic"; + EXPECT_EQ(kMode120, selector.getBestRefreshRate(layers)); + + lr1.desiredRefreshRate = 24_Hz; + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.name = "24Hz ExplicitExactOrMultiple"; + lr2.desiredRefreshRate = 60_Hz; + lr2.vote = LayerVoteType::Heuristic; + lr2.name = "60Hz Heuristic"; + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); + + lr1.desiredRefreshRate = 24_Hz; + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.name = "24Hz ExplicitExactOrMultiple"; + lr2.desiredRefreshRate = 60_Hz; + lr2.vote = LayerVoteType::ExplicitDefault; + lr2.name = "60Hz ExplicitDefault"; + EXPECT_EQ(kMode72, selector.getBestRefreshRate(layers)); + + lr1.desiredRefreshRate = 24_Hz; + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.name = "24Hz ExplicitExactOrMultiple"; + lr2.desiredRefreshRate = 90_Hz; + lr2.vote = LayerVoteType::Heuristic; + lr2.name = "90Hz Heuristic"; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr1.desiredRefreshRate = 24_Hz; + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.name = "24Hz ExplicitExactOrMultiple"; + lr2.desiredRefreshRate = 90_Hz; + lr2.vote = LayerVoteType::ExplicitDefault; + lr2.name = "90Hz Heuristic"; + EXPECT_EQ(kMode72, selector.getBestRefreshRate(layers)); + + lr1.desiredRefreshRate = 24_Hz; + lr1.vote = LayerVoteType::ExplicitDefault; + lr1.name = "24Hz ExplicitDefault"; + lr2.desiredRefreshRate = 90_Hz; + lr2.vote = LayerVoteType::Heuristic; + lr2.name = "90Hz Heuristic"; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr1.desiredRefreshRate = 24_Hz; + lr1.vote = LayerVoteType::Heuristic; + lr1.name = "24Hz Heuristic"; + lr2.desiredRefreshRate = 90_Hz; + lr2.vote = LayerVoteType::ExplicitDefault; + lr2.name = "90Hz ExplicitDefault"; + EXPECT_EQ(kMode72, selector.getBestRefreshRate(layers)); + + lr1.desiredRefreshRate = 24_Hz; + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.name = "24Hz ExplicitExactOrMultiple"; + lr2.desiredRefreshRate = 90_Hz; + lr2.vote = LayerVoteType::ExplicitDefault; + lr2.name = "90Hz ExplicitDefault"; + EXPECT_EQ(kMode72, selector.getBestRefreshRate(layers)); + + lr1.desiredRefreshRate = 24_Hz; + lr1.vote = LayerVoteType::ExplicitDefault; + lr1.name = "24Hz ExplicitDefault"; + lr2.desiredRefreshRate = 90_Hz; + lr2.vote = LayerVoteType::ExplicitExactOrMultiple; + lr2.name = "90Hz ExplicitExactOrMultiple"; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr1.desiredRefreshRate = 24_Hz; + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.name = "24Hz ExplicitExactOrMultiple"; + lr2.vote = LayerVoteType::Max; + lr2.name = "Max"; + EXPECT_EQ(kMode120, selector.getBestRefreshRate(layers)); + + lr1.desiredRefreshRate = 24_Hz; + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.name = "24Hz ExplicitExactOrMultiple"; + lr2.desiredRefreshRate = 120_Hz; + lr2.vote = LayerVoteType::ExplicitDefault; + lr2.name = "120Hz ExplicitDefault"; + EXPECT_EQ(kMode120, selector.getBestRefreshRate(layers)); + + lr1.desiredRefreshRate = 24_Hz; + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.name = "24Hz ExplicitExactOrMultiple"; + lr2.desiredRefreshRate = 120_Hz; + lr2.vote = LayerVoteType::ExplicitExact; + lr2.name = "120Hz ExplicitExact"; + EXPECT_EQ(kMode120, selector.getBestRefreshRate(layers)); + + lr1.desiredRefreshRate = 10_Hz; + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.name = "30Hz ExplicitExactOrMultiple"; + lr2.desiredRefreshRate = 120_Hz; + lr2.vote = LayerVoteType::Heuristic; + lr2.name = "120Hz ExplicitExact"; + EXPECT_EQ(kMode120, selector.getBestRefreshRate(layers)); + + lr1.desiredRefreshRate = 30_Hz; + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.name = "30Hz ExplicitExactOrMultiple"; + lr2.desiredRefreshRate = 30_Hz; + lr2.vote = LayerVoteType::ExplicitExactOrMultiple; + lr2.name = "30Hz ExplicitExactOrMultiple"; + lr3.vote = LayerVoteType::Heuristic; + lr3.desiredRefreshRate = 120_Hz; + lr3.name = "120Hz Heuristic"; + EXPECT_EQ(kMode120, selector.getBestRefreshRate(layers)); +} + +TEST_F(RefreshRateSelectorTest, getBestRefreshRate_30_60) { + TestableRefreshRateSelector selector(kModes_30_60, kModeId60); + + std::vector layers = {{.weight = 1.f}}; + auto& lr = layers[0]; + + lr.vote = LayerVoteType::Min; + EXPECT_EQ(kMode30, selector.getBestRefreshRate(layers)); + + lr.vote = LayerVoteType::Max; + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 90_Hz; + lr.vote = LayerVoteType::Heuristic; + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 60_Hz; + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 45_Hz; + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 30_Hz; + EXPECT_EQ(kMode30, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 24_Hz; + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); +} + +TEST_F(RefreshRateSelectorTest, getBestRefreshRate_30_60_72_90) { + TestableRefreshRateSelector selector(kModes_30_60_72_90, kModeId60); + + std::vector layers = {{.weight = 1.f}}; + auto& lr = layers[0]; + + lr.vote = LayerVoteType::Min; + lr.name = "Min"; + EXPECT_EQ(kMode30, selector.getBestRefreshRate(layers)); + + lr.vote = LayerVoteType::Max; + lr.name = "Max"; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 90_Hz; + lr.vote = LayerVoteType::Heuristic; + lr.name = "90Hz Heuristic"; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr.desiredRefreshRate = 60_Hz; + lr.name = "60Hz Heuristic"; + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers, {.touch = true})); + + lr.desiredRefreshRate = 45_Hz; + lr.name = "45Hz Heuristic"; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers, {.touch = true})); + + lr.desiredRefreshRate = 30_Hz; + lr.name = "30Hz Heuristic"; + EXPECT_EQ(kMode30, selector.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers, {.touch = true})); + + lr.desiredRefreshRate = 24_Hz; + lr.name = "24Hz Heuristic"; + EXPECT_EQ(kMode72, selector.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers, {.touch = true})); + + lr.desiredRefreshRate = 24_Hz; + lr.vote = LayerVoteType::ExplicitExactOrMultiple; + lr.name = "24Hz ExplicitExactOrMultiple"; + EXPECT_EQ(kMode72, selector.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers, {.touch = true})); +} + +TEST_F(RefreshRateSelectorTest, getBestRefreshRate_PriorityTest) { + TestableRefreshRateSelector selector(kModes_30_60_90, kModeId60); + + std::vector layers = {{.weight = 1.f}, {.weight = 1.f}}; + auto& lr1 = layers[0]; + auto& lr2 = layers[1]; + + lr1.vote = LayerVoteType::Min; + lr2.vote = LayerVoteType::Max; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr1.vote = LayerVoteType::Min; + lr2.vote = LayerVoteType::Heuristic; + lr2.desiredRefreshRate = 24_Hz; + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); + + lr1.vote = LayerVoteType::Min; + lr2.vote = LayerVoteType::ExplicitExactOrMultiple; + lr2.desiredRefreshRate = 24_Hz; + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); + + lr1.vote = LayerVoteType::Max; + lr2.vote = LayerVoteType::Heuristic; + lr2.desiredRefreshRate = 60_Hz; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr1.vote = LayerVoteType::Max; + lr2.vote = LayerVoteType::ExplicitExactOrMultiple; + lr2.desiredRefreshRate = 60_Hz; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr1.vote = LayerVoteType::Heuristic; + lr1.desiredRefreshRate = 15_Hz; + lr2.vote = LayerVoteType::Heuristic; + lr2.desiredRefreshRate = 45_Hz; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr1.vote = LayerVoteType::Heuristic; + lr1.desiredRefreshRate = 30_Hz; + lr2.vote = LayerVoteType::ExplicitExactOrMultiple; + lr2.desiredRefreshRate = 45_Hz; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); +} + +TEST_F(RefreshRateSelectorTest, getBestRefreshRate_24FpsVideo) { + TestableRefreshRateSelector selector(kModes_60_90, kModeId60); + + std::vector layers = {{.weight = 1.f}}; + auto& lr = layers[0]; + + lr.vote = LayerVoteType::ExplicitExactOrMultiple; + for (float fps = 23.0f; fps < 25.0f; fps += 0.1f) { + lr.desiredRefreshRate = Fps::fromValue(fps); + const auto mode = selector.getBestRefreshRate(layers); + EXPECT_EQ(kMode60, mode) << lr.desiredRefreshRate << " chooses " + << to_string(mode->getFps()); + } +} + +TEST_F(RefreshRateSelectorTest, getBestRefreshRate_24FpsVideo_multipleThreshold_60_120) { + TestableRefreshRateSelector selector(kModes_60_120, kModeId60, + {.frameRateMultipleThreshold = 120}); + + std::vector layers = {{.weight = 1.f}}; + auto& lr = layers[0]; + + lr.vote = LayerVoteType::ExplicitExactOrMultiple; + for (float fps = 23.0f; fps < 25.0f; fps += 0.1f) { + lr.desiredRefreshRate = Fps::fromValue(fps); + const auto mode = selector.getBestRefreshRate(layers); + EXPECT_EQ(kMode60, mode) << lr.desiredRefreshRate << " chooses " + << to_string(mode->getFps()); + } +} + +TEST_F(RefreshRateSelectorTest, twoModes_getBestRefreshRate_Explicit) { + TestableRefreshRateSelector selector(kModes_60_90, kModeId60); + + std::vector layers = {{.weight = 1.f}, {.weight = 1.f}}; + auto& lr1 = layers[0]; + auto& lr2 = layers[1]; + + lr1.vote = LayerVoteType::Heuristic; + lr1.desiredRefreshRate = 60_Hz; + lr2.vote = LayerVoteType::ExplicitExactOrMultiple; + lr2.desiredRefreshRate = 90_Hz; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr1.vote = LayerVoteType::ExplicitDefault; + lr1.desiredRefreshRate = 90_Hz; + lr2.vote = LayerVoteType::ExplicitExactOrMultiple; + lr2.desiredRefreshRate = 60_Hz; + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); + + lr1.vote = LayerVoteType::Heuristic; + lr1.desiredRefreshRate = 90_Hz; + lr2.vote = LayerVoteType::ExplicitExactOrMultiple; + lr2.desiredRefreshRate = 60_Hz; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); +} + +TEST_F(RefreshRateSelectorTest, getBestRefreshRate_75HzContent) { + TestableRefreshRateSelector selector(kModes_60_90, kModeId60); + + std::vector layers = {{.weight = 1.f}}; + auto& lr = layers[0]; + + lr.vote = LayerVoteType::ExplicitExactOrMultiple; + for (float fps = 75.0f; fps < 100.0f; fps += 0.1f) { + lr.desiredRefreshRate = Fps::fromValue(fps); + const auto mode = selector.getBestRefreshRate(layers, {}); + EXPECT_EQ(kMode90, mode) << lr.desiredRefreshRate << " chooses " + << to_string(mode->getFps()); + } +} + +TEST_F(RefreshRateSelectorTest, getBestRefreshRate_Multiples) { + TestableRefreshRateSelector selector(kModes_60_90, kModeId60); + + std::vector layers = {{.weight = 1.f}, {.weight = 1.f}}; + auto& lr1 = layers[0]; + auto& lr2 = layers[1]; + + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.desiredRefreshRate = 60_Hz; + lr1.name = "60Hz ExplicitExactOrMultiple"; + lr2.vote = LayerVoteType::Heuristic; + lr2.desiredRefreshRate = 90_Hz; + lr2.name = "90Hz Heuristic"; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.desiredRefreshRate = 60_Hz; + lr1.name = "60Hz ExplicitExactOrMultiple"; + lr2.vote = LayerVoteType::ExplicitDefault; + lr2.desiredRefreshRate = 90_Hz; + lr2.name = "90Hz ExplicitDefault"; + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); + + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.desiredRefreshRate = 60_Hz; + lr1.name = "60Hz ExplicitExactOrMultiple"; + lr2.vote = LayerVoteType::Max; + lr2.name = "Max"; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.desiredRefreshRate = 30_Hz; + lr1.name = "30Hz ExplicitExactOrMultiple"; + lr2.vote = LayerVoteType::Heuristic; + lr2.desiredRefreshRate = 90_Hz; + lr2.name = "90Hz Heuristic"; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.desiredRefreshRate = 30_Hz; + lr1.name = "30Hz ExplicitExactOrMultiple"; + lr2.vote = LayerVoteType::Max; + lr2.name = "Max"; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); +} + +TEST_F(RefreshRateSelectorTest, scrollWhileWatching60fps_60_90) { + TestableRefreshRateSelector selector(kModes_60_90, kModeId60); + + std::vector layers = {{.weight = 1.f}, {.weight = 1.f}}; + auto& lr1 = layers[0]; + auto& lr2 = layers[1]; + + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.desiredRefreshRate = 60_Hz; + lr1.name = "60Hz ExplicitExactOrMultiple"; + lr2.vote = LayerVoteType::NoVote; + lr2.name = "NoVote"; + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); + + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.desiredRefreshRate = 60_Hz; + lr1.name = "60Hz ExplicitExactOrMultiple"; + lr2.vote = LayerVoteType::NoVote; + lr2.name = "NoVote"; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers, {.touch = true})); + + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.desiredRefreshRate = 60_Hz; + lr1.name = "60Hz ExplicitExactOrMultiple"; + lr2.vote = LayerVoteType::Max; + lr2.name = "Max"; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers, {.touch = true})); + + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.desiredRefreshRate = 60_Hz; + lr1.name = "60Hz ExplicitExactOrMultiple"; + lr2.vote = LayerVoteType::Max; + lr2.name = "Max"; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + // The other layer starts to provide buffers + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.desiredRefreshRate = 60_Hz; + lr1.name = "60Hz ExplicitExactOrMultiple"; + lr2.vote = LayerVoteType::Heuristic; + lr2.desiredRefreshRate = 90_Hz; + lr2.name = "90Hz Heuristic"; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); +} + +TEST_F(RefreshRateSelectorTest, getMaxRefreshRatesByPolicy) { + // The kModes_30_60_90 contains two kMode72_G1, kMode120_G1 which are from the + // different group. + TestableRefreshRateSelector selector(kModes_30_60_90, kModeId60); + + const auto refreshRates = selector.rankRefreshRates(selector.getActiveMode().getGroup(), + RefreshRateOrder::Descending); + + const std::array expectedRefreshRates = {kMode90, kMode60, kMode30}; + ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size()); + + for (size_t i = 0; i < expectedRefreshRates.size(); ++i) { + EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].modePtr) + << "Expected fps " << expectedRefreshRates[i]->getFps().getIntValue() + << " Actual fps " << refreshRates[i].modePtr->getFps().getIntValue(); + } +} + +TEST_F(RefreshRateSelectorTest, getMinRefreshRatesByPolicy) { + // The kModes_30_60_90 contains two kMode72_G1, kMode120_G1 which are from the + // different group. + TestableRefreshRateSelector selector(kModes_30_60_90, kModeId60); + + const auto refreshRates = selector.rankRefreshRates(selector.getActiveMode().getGroup(), + RefreshRateOrder::Ascending); + + const std::array expectedRefreshRates = {kMode30, kMode60, kMode90}; + ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size()); + + for (size_t i = 0; i < expectedRefreshRates.size(); ++i) { + EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].modePtr) + << "Expected fps " << expectedRefreshRates[i]->getFps().getIntValue() + << " Actual fps " << refreshRates[i].modePtr->getFps().getIntValue(); + } +} + +TEST_F(RefreshRateSelectorTest, getMinRefreshRatesByPolicyOutsideTheGroup) { + // The kModes_30_60_90 contains two kMode72_G1, kMode120_G1 which are from the + // different group. + TestableRefreshRateSelector selector(kModes_30_60_90, kModeId72); + + EXPECT_EQ(SetPolicyResult::Changed, + selector.setDisplayManagerPolicy({kModeId60, {30_Hz, 90_Hz}, {30_Hz, 90_Hz}})); + + const auto refreshRates = + selector.rankRefreshRates(/*anchorGroupOpt*/ std::nullopt, RefreshRateOrder::Ascending); + + const std::array expectedRefreshRates = {kMode30, kMode60, kMode90}; + ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size()); + + for (size_t i = 0; i < expectedRefreshRates.size(); ++i) { + EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].modePtr) + << "Expected fps " << expectedRefreshRates[i]->getFps().getIntValue() + << " Actual fps " << refreshRates[i].modePtr->getFps().getIntValue(); + } +} + +TEST_F(RefreshRateSelectorTest, getMaxRefreshRatesByPolicyOutsideTheGroup) { + // The kModes_30_60_90 contains two kMode72_G1, kMode120_G1 which are from the + // different group. + TestableRefreshRateSelector selector(kModes_30_60_90, kModeId72); + + EXPECT_EQ(SetPolicyResult::Changed, + selector.setDisplayManagerPolicy({kModeId60, {30_Hz, 90_Hz}, {30_Hz, 90_Hz}})); + + const auto refreshRates = selector.rankRefreshRates(/*anchorGroupOpt*/ std::nullopt, + RefreshRateOrder::Descending); + + const std::array expectedRefreshRates = {kMode90, kMode60, kMode30}; + ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size()); + + for (size_t i = 0; i < expectedRefreshRates.size(); ++i) { + EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].modePtr) + << "Expected fps " << expectedRefreshRates[i]->getFps().getIntValue() + << " Actual fps " << refreshRates[i].modePtr->getFps().getIntValue(); + } +} + +TEST_F(RefreshRateSelectorTest, powerOnImminentConsidered) { + TestableRefreshRateSelector selector(kModes_60_90, kModeId60); + + auto [refreshRates, signals] = selector.getRankedRefreshRates({}, {}); + EXPECT_FALSE(signals.powerOnImminent); + + std::array expectedRefreshRates = {kMode90, kMode60}; + ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size()); + + for (size_t i = 0; i < expectedRefreshRates.size(); ++i) { + EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].modePtr) + << "Expected fps " << expectedRefreshRates[i]->getFps().getIntValue() + << " Actual fps " << refreshRates[i].modePtr->getFps().getIntValue(); + } + + std::tie(refreshRates, signals) = + selector.getRankedRefreshRatesAsPair({}, {.powerOnImminent = true}); + EXPECT_TRUE(signals.powerOnImminent); + + ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size()); + + for (size_t i = 0; i < expectedRefreshRates.size(); ++i) { + EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].modePtr) + << "Expected fps " << expectedRefreshRates[i]->getFps().getIntValue() + << " Actual fps " << refreshRates[i].modePtr->getFps().getIntValue(); + } + + std::vector layers = {{.weight = 1.f}}; + auto& lr1 = layers[0]; + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.desiredRefreshRate = 60_Hz; + lr1.name = "60Hz ExplicitExactOrMultiple"; + + std::tie(refreshRates, signals) = + selector.getRankedRefreshRatesAsPair(layers, {.powerOnImminent = true}); + EXPECT_TRUE(signals.powerOnImminent); + + ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size()); + + for (size_t i = 0; i < expectedRefreshRates.size(); ++i) { + EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].modePtr) + << "Expected fps " << expectedRefreshRates[i]->getFps().getIntValue() + << " Actual fps " << refreshRates[i].modePtr->getFps().getIntValue(); + } + + std::tie(refreshRates, signals) = + selector.getRankedRefreshRatesAsPair(layers, {.powerOnImminent = false}); + EXPECT_FALSE(signals.powerOnImminent); + + expectedRefreshRates = {kMode60, kMode90}; + ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size()); + + for (size_t i = 0; i < expectedRefreshRates.size(); ++i) { + EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].modePtr) + << "Expected fps " << expectedRefreshRates[i]->getFps().getIntValue() + << " Actual fps " << refreshRates[i].modePtr->getFps().getIntValue(); + } +} + +TEST_F(RefreshRateSelectorTest, touchConsidered) { + TestableRefreshRateSelector selector(kModes_60_90, kModeId60); + + auto [_, signals] = selector.getRankedRefreshRates({}, {}); + EXPECT_FALSE(signals.touch); + + std::tie(std::ignore, signals) = selector.getRankedRefreshRatesAsPair({}, {.touch = true}); + EXPECT_TRUE(signals.touch); + + std::vector layers = {{.weight = 1.f}, {.weight = 1.f}}; + auto& lr1 = layers[0]; + auto& lr2 = layers[1]; + + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.desiredRefreshRate = 60_Hz; + lr1.name = "60Hz ExplicitExactOrMultiple"; + lr2.vote = LayerVoteType::Heuristic; + lr2.desiredRefreshRate = 60_Hz; + lr2.name = "60Hz Heuristic"; + std::tie(std::ignore, signals) = selector.getRankedRefreshRatesAsPair(layers, {.touch = true}); + EXPECT_TRUE(signals.touch); + + lr1.vote = LayerVoteType::ExplicitDefault; + lr1.desiredRefreshRate = 60_Hz; + lr1.name = "60Hz ExplicitDefault"; + lr2.vote = LayerVoteType::Heuristic; + lr2.desiredRefreshRate = 60_Hz; + lr2.name = "60Hz Heuristic"; + std::tie(std::ignore, signals) = selector.getRankedRefreshRatesAsPair(layers, {.touch = true}); + EXPECT_FALSE(signals.touch); + + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.desiredRefreshRate = 60_Hz; + lr1.name = "60Hz ExplicitExactOrMultiple"; + lr2.vote = LayerVoteType::Heuristic; + lr2.desiredRefreshRate = 60_Hz; + lr2.name = "60Hz Heuristic"; + std::tie(std::ignore, signals) = selector.getRankedRefreshRatesAsPair(layers, {.touch = true}); + EXPECT_TRUE(signals.touch); + + lr1.vote = LayerVoteType::ExplicitDefault; + lr1.desiredRefreshRate = 60_Hz; + lr1.name = "60Hz ExplicitDefault"; + lr2.vote = LayerVoteType::Heuristic; + lr2.desiredRefreshRate = 60_Hz; + lr2.name = "60Hz Heuristic"; + std::tie(std::ignore, signals) = selector.getRankedRefreshRatesAsPair(layers, {.touch = true}); + EXPECT_FALSE(signals.touch); +} + +TEST_F(RefreshRateSelectorTest, getBestRefreshRate_ExplicitDefault) { + TestableRefreshRateSelector selector(kModes_60_90_72_120, kModeId60); + + std::vector layers = {{.weight = 1.f}}; + auto& lr = layers[0]; + + // Prepare a table with the vote and the expected refresh rate + const std::initializer_list> testCases = { + {130_Hz, 120_Hz}, {120_Hz, 120_Hz}, {119_Hz, 120_Hz}, {110_Hz, 120_Hz}, + + {100_Hz, 90_Hz}, {90_Hz, 90_Hz}, {89_Hz, 90_Hz}, + + {80_Hz, 72_Hz}, {73_Hz, 72_Hz}, {72_Hz, 72_Hz}, {71_Hz, 72_Hz}, {70_Hz, 72_Hz}, + + {65_Hz, 60_Hz}, {60_Hz, 60_Hz}, {59_Hz, 60_Hz}, {58_Hz, 60_Hz}, + + {55_Hz, 90_Hz}, {50_Hz, 90_Hz}, {45_Hz, 90_Hz}, + + {42_Hz, 120_Hz}, {40_Hz, 120_Hz}, {39_Hz, 120_Hz}, + + {37_Hz, 72_Hz}, {36_Hz, 72_Hz}, {35_Hz, 72_Hz}, + + {30_Hz, 60_Hz}, + }; + + for (auto [desired, expected] : testCases) { + lr.vote = LayerVoteType::ExplicitDefault; + lr.desiredRefreshRate = desired; + + std::stringstream ss; + ss << "ExplicitDefault " << desired; + lr.name = ss.str(); + + EXPECT_EQ(expected, selector.getBestRefreshRate(layers)->getFps()); + } +} + +TEST_F(RefreshRateSelectorTest, + getBestRefreshRate_ExplicitExactOrMultiple_WithFractionalRefreshRates) { + std::vector layers = {{.weight = 1.f}}; + auto& lr = layers[0]; + + // Test that 23.976 will choose 24 if 23.976 is not supported + { + TestableRefreshRateSelector selector(makeModes(kMode24, kMode25, kMode30, kMode30Frac, + kMode60, kMode60Frac), + kModeId60); + + lr.vote = LayerVoteType::ExplicitExactOrMultiple; + lr.desiredRefreshRate = 23.976_Hz; + lr.name = "ExplicitExactOrMultiple 23.976 Hz"; + EXPECT_EQ(kModeId24, selector.getBestRefreshRate(layers)->getId()); + } + + // Test that 24 will choose 23.976 if 24 is not supported + { + TestableRefreshRateSelector selector(makeModes(kMode24Frac, kMode25, kMode30, kMode30Frac, + kMode60, kMode60Frac), + kModeId60); + + lr.desiredRefreshRate = 24_Hz; + lr.name = "ExplicitExactOrMultiple 24 Hz"; + EXPECT_EQ(kModeId24Frac, selector.getBestRefreshRate(layers)->getId()); + } + + // Test that 29.97 will prefer 59.94 over 60 and 30 + { + TestableRefreshRateSelector selector(makeModes(kMode24, kMode24Frac, kMode25, kMode30, + kMode60, kMode60Frac), + kModeId60); + + lr.desiredRefreshRate = 29.97_Hz; + lr.name = "ExplicitExactOrMultiple 29.97 Hz"; + EXPECT_EQ(kModeId60Frac, selector.getBestRefreshRate(layers)->getId()); + } +} + +TEST_F(RefreshRateSelectorTest, getBestRefreshRate_ExplicitExact_WithFractionalRefreshRates) { + std::vector layers = {{.weight = 1.f}}; + auto& lr = layers[0]; + + // Test that voting for supported refresh rate will select this refresh rate + { + TestableRefreshRateSelector selector(kModes_24_25_30_50_60_Frac, kModeId60); + + for (auto desired : {23.976_Hz, 24_Hz, 25_Hz, 29.97_Hz, 30_Hz, 50_Hz, 59.94_Hz, 60_Hz}) { + lr.vote = LayerVoteType::ExplicitExact; + lr.desiredRefreshRate = desired; + std::stringstream ss; + ss << "ExplicitExact " << desired; + lr.name = ss.str(); + + EXPECT_EQ(lr.desiredRefreshRate, selector.getBestRefreshRate(layers)->getFps()); + } + } +} + +TEST_F(RefreshRateSelectorTest, + getBestRefreshRate_withDisplayManagerRequestingSingleRate_ignoresTouchFlag) { + TestableRefreshRateSelector selector(kModes_60_90, kModeId90); + + EXPECT_EQ(SetPolicyResult::Changed, + selector.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}, {60_Hz, 90_Hz}})); + + std::vector layers = {{.weight = 1.f}}; + auto& lr = layers[0]; + + lr.vote = LayerVoteType::ExplicitDefault; + lr.desiredRefreshRate = 60_Hz; + lr.name = "60Hz ExplicitDefault"; + lr.focused = true; + + const auto [mode, signals] = + selector.getRankedRefreshRates(layers, {.touch = true, .idle = true}); + + EXPECT_EQ(mode.begin()->modePtr, kMode60); + EXPECT_FALSE(signals.touch); +} + +TEST_F(RefreshRateSelectorTest, + getBestRefreshRate_withDisplayManagerRequestingSingleRate_ignoresIdleFlag) { + TestableRefreshRateSelector selector(kModes_60_90, kModeId60); + + EXPECT_EQ(SetPolicyResult::Changed, + selector.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}, {60_Hz, 90_Hz}})); + + std::vector layers = {{.weight = 1.f}}; + auto& lr = layers[0]; + + lr.vote = LayerVoteType::ExplicitDefault; + lr.desiredRefreshRate = 90_Hz; + lr.name = "90Hz ExplicitDefault"; + lr.focused = true; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers, {.idle = true})); +} + +TEST_F(RefreshRateSelectorTest, testDisplayModeOrdering) { + TestableRefreshRateSelector selector(kModes_30_60_72_90_120, kModeId60); + + std::vector layers = {{.weight = 1.f}, + {.weight = 1.f}, + {.weight = 1.f}, + {.weight = 1.f}, + {.weight = 1.f}}; + auto& lr1 = layers[0]; + auto& lr2 = layers[1]; + auto& lr3 = layers[2]; + auto& lr4 = layers[3]; + auto& lr5 = layers[4]; + + lr1.desiredRefreshRate = 90_Hz; + lr1.name = "90Hz"; + lr1.focused = true; + + lr2.desiredRefreshRate = 60_Hz; + lr2.name = "60Hz"; + lr2.focused = true; + + lr3.desiredRefreshRate = 72_Hz; + lr3.name = "72Hz"; + lr3.focused = true; + + lr4.desiredRefreshRate = 120_Hz; + lr4.name = "120Hz"; + lr4.focused = true; + + lr5.desiredRefreshRate = 30_Hz; + lr5.name = "30Hz"; + lr5.focused = true; + + std::array expectedRanking = {kMode120, kMode90, kMode72, kMode60, kMode30}; + auto actualRanking = selector.getRankedRefreshRates(layers, {}).ranking; + + ASSERT_EQ(expectedRanking.size(), actualRanking.size()); + + for (size_t i = 0; i < expectedRanking.size(); ++i) { + EXPECT_EQ(expectedRanking[i], actualRanking[i].modePtr) + << "Expected fps " << expectedRanking[i]->getFps().getIntValue() << " Actual fps " + << actualRanking[i].modePtr->getFps().getIntValue(); + } + + lr1.vote = LayerVoteType::Max; + lr1.name = "Max"; + + lr2.desiredRefreshRate = 60_Hz; + lr2.name = "60Hz"; + + lr3.desiredRefreshRate = 72_Hz; + lr3.name = "72Hz"; + + lr4.desiredRefreshRate = 90_Hz; + lr4.name = "90Hz"; + + lr5.desiredRefreshRate = 120_Hz; + lr5.name = "120Hz"; + + expectedRanking = {kMode120, kMode90, kMode72, kMode60, kMode30}; + actualRanking = selector.getRankedRefreshRates(layers, {}).ranking; + + ASSERT_EQ(expectedRanking.size(), actualRanking.size()); + + for (size_t i = 0; i < expectedRanking.size(); ++i) { + EXPECT_EQ(expectedRanking[i], actualRanking[i].modePtr) + << "Expected fps " << expectedRanking[i]->getFps().getIntValue() << " Actual fps " + << actualRanking[i].modePtr->getFps().getIntValue(); + } + + lr1.vote = LayerVoteType::Heuristic; + lr1.desiredRefreshRate = 30_Hz; + lr1.name = "30Hz"; + + lr2.desiredRefreshRate = 120_Hz; + lr2.name = "120Hz"; + + lr3.desiredRefreshRate = 60_Hz; + lr3.name = "60Hz"; + + lr5.desiredRefreshRate = 72_Hz; + lr5.name = "72Hz"; + + expectedRanking = {kMode30, kMode60, kMode90, kMode120, kMode72}; + actualRanking = selector.getRankedRefreshRates(layers, {}).ranking; + + ASSERT_EQ(expectedRanking.size(), actualRanking.size()); + + for (size_t i = 0; i < expectedRanking.size(); ++i) { + EXPECT_EQ(expectedRanking[i], actualRanking[i].modePtr) + << "Expected fps " << expectedRanking[i]->getFps().getIntValue() << " Actual fps " + << actualRanking[i].modePtr->getFps().getIntValue(); + } + + lr1.desiredRefreshRate = 120_Hz; + lr1.name = "120Hz"; + lr1.weight = 0.0f; + + lr2.desiredRefreshRate = 60_Hz; + lr2.name = "60Hz"; + lr2.vote = LayerVoteType::NoVote; + + lr3.name = "60Hz-2"; + lr3.vote = LayerVoteType::Heuristic; + + lr4.vote = LayerVoteType::ExplicitExact; + + lr5.desiredRefreshRate = 120_Hz; + lr5.name = "120Hz-2"; + + expectedRanking = {kMode90, kMode60, kMode120, kMode72, kMode30}; + actualRanking = selector.getRankedRefreshRates(layers, {}).ranking; + + ASSERT_EQ(expectedRanking.size(), actualRanking.size()); + + for (size_t i = 0; i < expectedRanking.size(); ++i) { + EXPECT_EQ(expectedRanking[i], actualRanking[i].modePtr) + << "Expected fps " << expectedRanking[i]->getFps().getIntValue() << " Actual fps " + << actualRanking[i].modePtr->getFps().getIntValue(); + } +} + +TEST_F(RefreshRateSelectorTest, + getBestRefreshRate_withDisplayManagerRequestingSingleRate_onlySwitchesRatesForExplicitFocusedLayers) { + TestableRefreshRateSelector selector(kModes_60_90, kModeId90); + + EXPECT_EQ(SetPolicyResult::Changed, + selector.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}, {60_Hz, 90_Hz}})); + + const auto [ranking, signals] = selector.getRankedRefreshRates({}, {}); + EXPECT_EQ(ranking.front().modePtr, kMode90); + EXPECT_FALSE(signals.touch); + + std::vector layers = {{.weight = 1.f}}; + auto& lr = layers[0]; + + lr.vote = LayerVoteType::ExplicitExactOrMultiple; + lr.desiredRefreshRate = 60_Hz; + lr.name = "60Hz ExplicitExactOrMultiple"; + lr.focused = false; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr.focused = true; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr.vote = LayerVoteType::ExplicitDefault; + lr.desiredRefreshRate = 60_Hz; + lr.name = "60Hz ExplicitDefault"; + lr.focused = false; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr.focused = true; + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); + + lr.vote = LayerVoteType::Heuristic; + lr.desiredRefreshRate = 60_Hz; + lr.name = "60Hz Heuristic"; + lr.focused = false; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr.focused = true; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr.vote = LayerVoteType::Max; + lr.desiredRefreshRate = 60_Hz; + lr.name = "60Hz Max"; + lr.focused = false; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr.focused = true; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr.vote = LayerVoteType::Min; + lr.desiredRefreshRate = 60_Hz; + lr.name = "60Hz Min"; + lr.focused = false; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + lr.focused = true; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); +} + +TEST_F(RefreshRateSelectorTest, groupSwitchingNotAllowed) { + TestableRefreshRateSelector selector(kModes_60_90_G1, kModeId60); + + // The default policy doesn't allow group switching. Verify that no + // group switches are performed. + std::vector layers = {{.weight = 1.f}}; + auto& layer = layers[0]; + layer.vote = LayerVoteType::ExplicitDefault; + layer.desiredRefreshRate = 90_Hz; + layer.seamlessness = Seamlessness::SeamedAndSeamless; + layer.name = "90Hz ExplicitDefault"; + layer.focused = true; + + EXPECT_EQ(kModeId60, selector.getBestRefreshRate(layers)->getId()); +} + +TEST_F(RefreshRateSelectorTest, groupSwitchingWithOneLayer) { + TestableRefreshRateSelector selector(kModes_60_90_G1, kModeId60); + + RefreshRateSelector::DisplayManagerPolicy policy; + policy.defaultMode = selector.getCurrentPolicy().defaultMode; + policy.allowGroupSwitching = true; + EXPECT_EQ(SetPolicyResult::Changed, selector.setPolicy(policy)); + + std::vector layers = {{.weight = 1.f}}; + auto& layer = layers[0]; + layer.vote = LayerVoteType::ExplicitDefault; + layer.desiredRefreshRate = 90_Hz; + layer.seamlessness = Seamlessness::SeamedAndSeamless; + layer.name = "90Hz ExplicitDefault"; + layer.focused = true; + EXPECT_EQ(kModeId90, selector.getBestRefreshRate(layers)->getId()); +} + +TEST_F(RefreshRateSelectorTest, groupSwitchingWithOneLayerOnlySeamless) { + TestableRefreshRateSelector selector(kModes_60_90_G1, kModeId60); + + RefreshRateSelector::DisplayManagerPolicy policy; + policy.defaultMode = selector.getCurrentPolicy().defaultMode; + policy.allowGroupSwitching = true; + EXPECT_EQ(SetPolicyResult::Changed, selector.setPolicy(policy)); + + // Verify that we won't change the group if seamless switch is required. + std::vector layers = {{.weight = 1.f}}; + auto& layer = layers[0]; + layer.vote = LayerVoteType::ExplicitDefault; + layer.desiredRefreshRate = 90_Hz; + layer.seamlessness = Seamlessness::OnlySeamless; + layer.name = "90Hz ExplicitDefault"; + layer.focused = true; + EXPECT_EQ(kModeId60, selector.getBestRefreshRate(layers)->getId()); +} + +TEST_F(RefreshRateSelectorTest, groupSwitchingWithOneLayerOnlySeamlessDefaultFps) { + TestableRefreshRateSelector selector(kModes_60_90_G1, kModeId60); + + RefreshRateSelector::DisplayManagerPolicy policy; + policy.defaultMode = selector.getCurrentPolicy().defaultMode; + policy.allowGroupSwitching = true; + EXPECT_EQ(SetPolicyResult::Changed, selector.setPolicy(policy)); + + selector.setActiveModeId(kModeId90); + + // Verify that we won't do a seamless switch if we request the same mode as the default + std::vector layers = {{.weight = 1.f}}; + auto& layer = layers[0]; + layer.vote = LayerVoteType::ExplicitDefault; + layer.desiredRefreshRate = 60_Hz; + layer.seamlessness = Seamlessness::OnlySeamless; + layer.name = "60Hz ExplicitDefault"; + layer.focused = true; + EXPECT_EQ(kModeId90, selector.getBestRefreshRate(layers)->getId()); +} + +TEST_F(RefreshRateSelectorTest, groupSwitchingWithOneLayerDefaultSeamlessness) { + TestableRefreshRateSelector selector(kModes_60_90_G1, kModeId60); + + RefreshRateSelector::DisplayManagerPolicy policy; + policy.defaultMode = selector.getCurrentPolicy().defaultMode; + policy.allowGroupSwitching = true; + EXPECT_EQ(SetPolicyResult::Changed, selector.setPolicy(policy)); + + selector.setActiveModeId(kModeId90); + + // Verify that if the active mode is in another group and there are no layers with + // Seamlessness::SeamedAndSeamless, we should switch back to the default group. + + std::vector layers = {{.weight = 1.f}}; + auto& layer = layers[0]; + layer.vote = LayerVoteType::ExplicitDefault; + layer.desiredRefreshRate = 60_Hz; + layer.seamlessness = Seamlessness::Default; + layer.name = "60Hz ExplicitDefault"; + layer.focused = true; + + EXPECT_EQ(kModeId60, selector.getBestRefreshRate(layers)->getId()); +} + +TEST_F(RefreshRateSelectorTest, groupSwitchingWithTwoLayersOnlySeamlessAndSeamed) { + TestableRefreshRateSelector selector(kModes_60_90_G1, kModeId60); + + RefreshRateSelector::DisplayManagerPolicy policy; + policy.defaultMode = selector.getCurrentPolicy().defaultMode; + policy.allowGroupSwitching = true; + EXPECT_EQ(SetPolicyResult::Changed, selector.setPolicy(policy)); + + selector.setActiveModeId(kModeId90); + + // If there's a layer with Seamlessness::SeamedAndSeamless, another layer with + // Seamlessness::OnlySeamless can't change the mode group. + std::vector layers = {{.weight = 1.f}}; + layers[0].vote = LayerVoteType::ExplicitDefault; + layers[0].desiredRefreshRate = 60_Hz; + layers[0].seamlessness = Seamlessness::OnlySeamless; + layers[0].name = "60Hz ExplicitDefault"; + layers[0].focused = true; + + layers.push_back(LayerRequirement{.weight = 0.5f}); + layers[1].vote = LayerVoteType::ExplicitDefault; + layers[1].seamlessness = Seamlessness::SeamedAndSeamless; + layers[1].desiredRefreshRate = 90_Hz; + layers[1].name = "90Hz ExplicitDefault"; + layers[1].focused = false; + + EXPECT_EQ(kModeId90, selector.getBestRefreshRate(layers)->getId()); +} + +TEST_F(RefreshRateSelectorTest, groupSwitchingWithTwoLayersDefaultFocusedAndSeamed) { + TestableRefreshRateSelector selector(kModes_60_90_G1, kModeId60); + + RefreshRateSelector::DisplayManagerPolicy policy; + policy.defaultMode = selector.getCurrentPolicy().defaultMode; + policy.allowGroupSwitching = true; + EXPECT_EQ(SetPolicyResult::Changed, selector.setPolicy(policy)); + + selector.setActiveModeId(kModeId90); + + // If there's a focused layer with Seamlessness::SeamedAndSeamless, another layer with + // Seamlessness::Default can't change the mode group back to the group of the default + // mode. + // For example, this may happen when a video playback requests and gets a seamed switch, + // but another layer (with default seamlessness) starts animating. The animating layer + // should not cause a seamed switch. + std::vector layers = {{.weight = 1.f}}; + layers[0].seamlessness = Seamlessness::Default; + layers[0].desiredRefreshRate = 60_Hz; + layers[0].focused = true; + layers[0].vote = LayerVoteType::ExplicitDefault; + layers[0].name = "60Hz ExplicitDefault"; + + layers.push_back(LayerRequirement{.weight = 0.1f}); + layers[1].seamlessness = Seamlessness::SeamedAndSeamless; + layers[1].desiredRefreshRate = 90_Hz; + layers[1].focused = true; + layers[1].vote = LayerVoteType::ExplicitDefault; + layers[1].name = "90Hz ExplicitDefault"; + + EXPECT_EQ(kModeId90, selector.getBestRefreshRate(layers)->getId()); +} + +TEST_F(RefreshRateSelectorTest, groupSwitchingWithTwoLayersDefaultNotFocusedAndSeamed) { + TestableRefreshRateSelector selector(kModes_60_90_G1, kModeId60); + + RefreshRateSelector::DisplayManagerPolicy policy; + policy.defaultMode = selector.getCurrentPolicy().defaultMode; + policy.allowGroupSwitching = true; + EXPECT_EQ(SetPolicyResult::Changed, selector.setPolicy(policy)); + + selector.setActiveModeId(kModeId90); + + // Layer with Seamlessness::Default can change the mode group if there's an + // unfocused layer with Seamlessness::SeamedAndSeamless. For example, this happens + // when in split screen mode the user switches between the two visible applications. + std::vector layers = {{.weight = 1.f}}; + layers[0].seamlessness = Seamlessness::Default; + layers[0].desiredRefreshRate = 60_Hz; + layers[0].focused = true; + layers[0].vote = LayerVoteType::ExplicitDefault; + layers[0].name = "60Hz ExplicitDefault"; + + layers.push_back(LayerRequirement{.weight = 0.7f}); + layers[1].seamlessness = Seamlessness::SeamedAndSeamless; + layers[1].desiredRefreshRate = 90_Hz; + layers[1].focused = false; + layers[1].vote = LayerVoteType::ExplicitDefault; + layers[1].name = "90Hz ExplicitDefault"; + + EXPECT_EQ(kModeId60, selector.getBestRefreshRate(layers)->getId()); +} + +TEST_F(RefreshRateSelectorTest, nonSeamlessVotePrefersSeamlessSwitches) { + TestableRefreshRateSelector selector(kModes_30_60, kModeId60); + + // Allow group switching. + RefreshRateSelector::DisplayManagerPolicy policy; + policy.defaultMode = selector.getCurrentPolicy().defaultMode; + policy.allowGroupSwitching = true; + EXPECT_EQ(SetPolicyResult::Changed, selector.setPolicy(policy)); + + std::vector layers = {{.weight = 1.f}}; + auto& layer = layers[0]; + layer.vote = LayerVoteType::ExplicitExactOrMultiple; + layer.desiredRefreshRate = 60_Hz; + layer.seamlessness = Seamlessness::SeamedAndSeamless; + layer.name = "60Hz ExplicitExactOrMultiple"; + layer.focused = true; + + EXPECT_EQ(kModeId60, selector.getBestRefreshRate(layers)->getId()); + + selector.setActiveModeId(kModeId120); + EXPECT_EQ(kModeId120, selector.getBestRefreshRate(layers)->getId()); +} + +TEST_F(RefreshRateSelectorTest, nonSeamlessExactAndSeamlessMultipleLayers) { + TestableRefreshRateSelector selector(kModes_25_30_50_60, kModeId60); + + // Allow group switching. + RefreshRateSelector::DisplayManagerPolicy policy; + policy.defaultMode = selector.getCurrentPolicy().defaultMode; + policy.allowGroupSwitching = true; + EXPECT_EQ(SetPolicyResult::Changed, selector.setPolicy(policy)); + + std::vector layers = {{.name = "60Hz ExplicitDefault", + .vote = LayerVoteType::ExplicitDefault, + .desiredRefreshRate = 60_Hz, + .seamlessness = Seamlessness::SeamedAndSeamless, + .weight = 0.5f, + .focused = false}, + {.name = "25Hz ExplicitExactOrMultiple", + .vote = LayerVoteType::ExplicitExactOrMultiple, + .desiredRefreshRate = 25_Hz, + .seamlessness = Seamlessness::OnlySeamless, + .weight = 1.f, + .focused = true}}; + + EXPECT_EQ(kModeId50, selector.getBestRefreshRate(layers)->getId()); + + auto& seamedLayer = layers[0]; + seamedLayer.desiredRefreshRate = 30_Hz; + seamedLayer.name = "30Hz ExplicitDefault"; + selector.setActiveModeId(kModeId30); + + EXPECT_EQ(kModeId25, selector.getBestRefreshRate(layers)->getId()); +} + +TEST_F(RefreshRateSelectorTest, minLayersDontTrigerSeamedSwitch) { + TestableRefreshRateSelector selector(kModes_60_90_G1, kModeId90); + + // Allow group switching. + RefreshRateSelector::DisplayManagerPolicy policy; + policy.defaultMode = selector.getCurrentPolicy().defaultMode; + policy.allowGroupSwitching = true; + EXPECT_EQ(SetPolicyResult::Changed, selector.setPolicy(policy)); + + std::vector layers = { + {.name = "Min", .vote = LayerVoteType::Min, .weight = 1.f, .focused = true}}; + + EXPECT_EQ(kModeId90, selector.getBestRefreshRate(layers)->getId()); +} + +TEST_F(RefreshRateSelectorTest, primaryVsAppRequestPolicy) { + TestableRefreshRateSelector selector(kModes_30_60_90, kModeId60); + + std::vector layers = {{.weight = 1.f}}; + layers[0].name = "Test layer"; + + struct Args { + bool touch = false; + bool focused = true; + }; + + // Returns the mode selected by getBestRefreshRate for a single layer with the given arguments. + const auto getFrameRate = [&](LayerVoteType voteType, Fps fps, + Args args = {}) -> DisplayModeId { + layers[0].vote = voteType; + layers[0].desiredRefreshRate = fps; + layers[0].focused = args.focused; + return selector.getBestRefreshRate(layers, {.touch = args.touch})->getId(); + }; + + EXPECT_EQ(SetPolicyResult::Changed, + selector.setDisplayManagerPolicy({kModeId60, {30_Hz, 60_Hz}, {30_Hz, 90_Hz}})); + + EXPECT_EQ(kModeId60, selector.getBestRefreshRate()->getId()); + EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::NoVote, 90_Hz)); + EXPECT_EQ(kModeId30, getFrameRate(LayerVoteType::Min, 90_Hz)); + EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::Max, 90_Hz)); + EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::Heuristic, 90_Hz)); + EXPECT_EQ(kModeId90, getFrameRate(LayerVoteType::ExplicitDefault, 90_Hz)); + EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90_Hz)); + + // Unfocused layers are not allowed to override primary range. + EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::ExplicitDefault, 90_Hz, {.focused = false})); + EXPECT_EQ(kModeId60, + getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90_Hz, {.focused = false})); + + // Touch boost should be restricted to the primary range. + EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::Max, 90_Hz, {.touch = true})); + + // When we're higher than the primary range max due to a layer frame rate setting, touch boost + // shouldn't drag us back down to the primary range max. + EXPECT_EQ(kModeId90, getFrameRate(LayerVoteType::ExplicitDefault, 90_Hz, {.touch = true})); + EXPECT_EQ(kModeId60, + getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90_Hz, {.touch = true})); + + EXPECT_EQ(SetPolicyResult::Changed, + selector.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}, {60_Hz, 60_Hz}})); + + EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::NoVote, 90_Hz)); + EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::Min, 90_Hz)); + EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::Max, 90_Hz)); + EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::Heuristic, 90_Hz)); + EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::ExplicitDefault, 90_Hz)); + EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90_Hz)); +} + +TEST_F(RefreshRateSelectorTest, idle) { + TestableRefreshRateSelector selector(kModes_60_90, kModeId60); + + std::vector layers = {{.weight = 1.f}}; + layers[0].name = "Test layer"; + + const auto getIdleFrameRate = [&](LayerVoteType voteType, bool touchActive) -> DisplayModeId { + layers[0].vote = voteType; + layers[0].desiredRefreshRate = 90_Hz; + + const auto [ranking, signals] = + selector.getRankedRefreshRates(layers, {.touch = touchActive, .idle = true}); + + // Refresh rate will be chosen by either touch state or idle state. + EXPECT_EQ(!touchActive, signals.idle); + return ranking.front().modePtr->getId(); + }; + + EXPECT_EQ(SetPolicyResult::Changed, + selector.setDisplayManagerPolicy({kModeId60, {60_Hz, 90_Hz}, {60_Hz, 90_Hz}})); + + // Idle should be lower priority than touch boost. + { + constexpr bool kTouchActive = true; + EXPECT_EQ(kModeId90, getIdleFrameRate(LayerVoteType::NoVote, kTouchActive)); + EXPECT_EQ(kModeId90, getIdleFrameRate(LayerVoteType::Min, kTouchActive)); + EXPECT_EQ(kModeId90, getIdleFrameRate(LayerVoteType::Max, kTouchActive)); + EXPECT_EQ(kModeId90, getIdleFrameRate(LayerVoteType::Heuristic, kTouchActive)); + EXPECT_EQ(kModeId90, getIdleFrameRate(LayerVoteType::ExplicitDefault, kTouchActive)); + EXPECT_EQ(kModeId90, + getIdleFrameRate(LayerVoteType::ExplicitExactOrMultiple, kTouchActive)); + } + + // With no layers, idle should still be lower priority than touch boost. + EXPECT_EQ(kModeId90, selector.getBestRefreshRate({}, {.touch = true, .idle = true})->getId()); + + // Idle should be higher precedence than other layer frame rate considerations. + selector.setActiveModeId(kModeId90); + + { + constexpr bool kTouchActive = false; + EXPECT_EQ(kModeId60, getIdleFrameRate(LayerVoteType::NoVote, kTouchActive)); + EXPECT_EQ(kModeId60, getIdleFrameRate(LayerVoteType::Min, kTouchActive)); + EXPECT_EQ(kModeId60, getIdleFrameRate(LayerVoteType::Max, kTouchActive)); + EXPECT_EQ(kModeId60, getIdleFrameRate(LayerVoteType::Heuristic, kTouchActive)); + EXPECT_EQ(kModeId60, getIdleFrameRate(LayerVoteType::ExplicitDefault, kTouchActive)); + EXPECT_EQ(kModeId60, + getIdleFrameRate(LayerVoteType::ExplicitExactOrMultiple, kTouchActive)); + } + + // Idle should be applied rather than the active mode when there are no layers. + EXPECT_EQ(kModeId60, selector.getBestRefreshRate({}, {.idle = true})->getId()); +} + +TEST_F(RefreshRateSelectorTest, findClosestKnownFrameRate) { + TestableRefreshRateSelector selector(kModes_60_90, kModeId60); + + for (float fps = 1.0f; fps <= 120.0f; fps += 0.1f) { + const auto knownFrameRate = selector.findClosestKnownFrameRate(Fps::fromValue(fps)); + const Fps expectedFrameRate = [fps] { + if (fps < 26.91f) return 24_Hz; + if (fps < 37.51f) return 30_Hz; + if (fps < 52.51f) return 45_Hz; + if (fps < 66.01f) return 60_Hz; + if (fps < 81.01f) return 72_Hz; + return 90_Hz; + }(); + + EXPECT_EQ(expectedFrameRate, knownFrameRate); + } +} + +TEST_F(RefreshRateSelectorTest, getBestRefreshRate_KnownFrameRate) { + TestableRefreshRateSelector selector(kModes_60_90, kModeId60); + + struct Expectation { + Fps fps; + DisplayModePtr mode; + }; + + const std::initializer_list knownFrameRatesExpectations = { + {24_Hz, kMode60}, {30_Hz, kMode60}, {45_Hz, kMode90}, + {60_Hz, kMode60}, {72_Hz, kMode90}, {90_Hz, kMode90}, + }; + + // Make sure the test tests all the known frame rate + const auto& knownFrameRates = selector.knownFrameRates(); + const bool equal = std::equal(knownFrameRates.begin(), knownFrameRates.end(), + knownFrameRatesExpectations.begin(), + [](Fps fps, const Expectation& expected) { + return isApproxEqual(fps, expected.fps); + }); + EXPECT_TRUE(equal); + + std::vector layers = {{.weight = 1.f}}; + auto& layer = layers[0]; + layer.vote = LayerVoteType::Heuristic; + + for (const auto& [fps, mode] : knownFrameRatesExpectations) { + layer.desiredRefreshRate = fps; + EXPECT_EQ(mode, selector.getBestRefreshRate(layers)); + } +} + +TEST_F(RefreshRateSelectorTest, getBestRefreshRate_ExplicitExact) { + TestableRefreshRateSelector selector(kModes_30_60_72_90_120, kModeId60); + + std::vector layers = {{.weight = 1.f}, {.weight = 0.5f}}; + auto& explicitExactLayer = layers[0]; + auto& explicitExactOrMultipleLayer = layers[1]; + + explicitExactOrMultipleLayer.vote = LayerVoteType::ExplicitExactOrMultiple; + explicitExactOrMultipleLayer.name = "ExplicitExactOrMultiple"; + explicitExactOrMultipleLayer.desiredRefreshRate = 60_Hz; + + explicitExactLayer.vote = LayerVoteType::ExplicitExact; + explicitExactLayer.name = "ExplicitExact"; + explicitExactLayer.desiredRefreshRate = 30_Hz; + + EXPECT_EQ(kMode30, selector.getBestRefreshRate(layers)); + EXPECT_EQ(kMode30, selector.getBestRefreshRate(layers, {.touch = true})); + + explicitExactOrMultipleLayer.desiredRefreshRate = 120_Hz; + explicitExactLayer.desiredRefreshRate = 60_Hz; + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); + + explicitExactLayer.desiredRefreshRate = 72_Hz; + EXPECT_EQ(kMode72, selector.getBestRefreshRate(layers)); + + explicitExactLayer.desiredRefreshRate = 90_Hz; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + explicitExactLayer.desiredRefreshRate = 120_Hz; + EXPECT_EQ(kMode120, selector.getBestRefreshRate(layers)); +} + +TEST_F(RefreshRateSelectorTest, getBestRefreshRate_ExplicitExactEnableFrameRateOverride) { + TestableRefreshRateSelector selector(kModes_30_60_72_90_120, kModeId60, + {.enableFrameRateOverride = true}); + + std::vector layers = {{.weight = 1.f}, {.weight = 0.5f}}; + auto& explicitExactLayer = layers[0]; + auto& explicitExactOrMultipleLayer = layers[1]; + + explicitExactOrMultipleLayer.vote = LayerVoteType::ExplicitExactOrMultiple; + explicitExactOrMultipleLayer.name = "ExplicitExactOrMultiple"; + explicitExactOrMultipleLayer.desiredRefreshRate = 60_Hz; + + explicitExactLayer.vote = LayerVoteType::ExplicitExact; + explicitExactLayer.name = "ExplicitExact"; + explicitExactLayer.desiredRefreshRate = 30_Hz; + + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); + EXPECT_EQ(kMode120, selector.getBestRefreshRate(layers, {.touch = true})); + + explicitExactOrMultipleLayer.desiredRefreshRate = 120_Hz; + explicitExactLayer.desiredRefreshRate = 60_Hz; + EXPECT_EQ(kMode120, selector.getBestRefreshRate(layers)); + + explicitExactLayer.desiredRefreshRate = 72_Hz; + EXPECT_EQ(kMode72, selector.getBestRefreshRate(layers)); + + explicitExactLayer.desiredRefreshRate = 90_Hz; + EXPECT_EQ(kMode90, selector.getBestRefreshRate(layers)); + + explicitExactLayer.desiredRefreshRate = 120_Hz; + EXPECT_EQ(kMode120, selector.getBestRefreshRate(layers)); +} + +TEST_F(RefreshRateSelectorTest, getBestRefreshRate_ReadsCache) { + TestableRefreshRateSelector selector(kModes_30_60_72_90_120, kModeId60); + + using GlobalSignals = RefreshRateSelector::GlobalSignals; + const auto args = std::make_pair(std::vector{}, + GlobalSignals{.touch = true, .idle = true}); + + const RefreshRateSelector::RankedRefreshRates result = {{RefreshRateSelector::ScoredRefreshRate{ + kMode90}}, + {.touch = true}}; + + selector.mutableGetRankedRefreshRatesCache() = {args, result}; + + EXPECT_EQ(result, selector.getRankedRefreshRates(args.first, args.second)); +} + +TEST_F(RefreshRateSelectorTest, getBestRefreshRate_WritesCache) { + TestableRefreshRateSelector selector(kModes_30_60_72_90_120, kModeId60); + + EXPECT_FALSE(selector.mutableGetRankedRefreshRatesCache()); + + std::vector layers = {{.weight = 1.f}, {.weight = 0.5f}}; + RefreshRateSelector::GlobalSignals globalSignals{.touch = true, .idle = true}; + + const auto result = selector.getRankedRefreshRates(layers, globalSignals); + + const auto& cache = selector.mutableGetRankedRefreshRatesCache(); + ASSERT_TRUE(cache); + + EXPECT_EQ(cache->arguments, std::make_pair(layers, globalSignals)); + EXPECT_EQ(cache->result, result); +} + +TEST_F(RefreshRateSelectorTest, getBestRefreshRate_ExplicitExactTouchBoost) { + TestableRefreshRateSelector selector(kModes_60_120, kModeId60, + {.enableFrameRateOverride = true}); + + std::vector layers = {{.weight = 1.f}, {.weight = 0.5f}}; + auto& explicitExactLayer = layers[0]; + auto& explicitExactOrMultipleLayer = layers[1]; + + explicitExactOrMultipleLayer.vote = LayerVoteType::ExplicitExactOrMultiple; + explicitExactOrMultipleLayer.name = "ExplicitExactOrMultiple"; + explicitExactOrMultipleLayer.desiredRefreshRate = 60_Hz; + + explicitExactLayer.vote = LayerVoteType::ExplicitExact; + explicitExactLayer.name = "ExplicitExact"; + explicitExactLayer.desiredRefreshRate = 30_Hz; + + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); + EXPECT_EQ(kMode120, selector.getBestRefreshRate(layers, {.touch = true})); + + explicitExactOrMultipleLayer.vote = LayerVoteType::NoVote; + + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers, {.touch = true})); +} + +TEST_F(RefreshRateSelectorTest, getBestRefreshRate_FractionalRefreshRates_ExactAndDefault) { + TestableRefreshRateSelector selector(kModes_24_25_30_50_60_Frac, kModeId60, + {.enableFrameRateOverride = true}); + + std::vector layers = {{.weight = 0.5f}, {.weight = 0.5f}}; + auto& explicitDefaultLayer = layers[0]; + auto& explicitExactOrMultipleLayer = layers[1]; + + explicitExactOrMultipleLayer.vote = LayerVoteType::ExplicitExactOrMultiple; + explicitExactOrMultipleLayer.name = "ExplicitExactOrMultiple"; + explicitExactOrMultipleLayer.desiredRefreshRate = 60_Hz; + + explicitDefaultLayer.vote = LayerVoteType::ExplicitDefault; + explicitDefaultLayer.name = "ExplicitDefault"; + explicitDefaultLayer.desiredRefreshRate = 59.94_Hz; + + EXPECT_EQ(kMode60, selector.getBestRefreshRate(layers)); +} + +// b/190578904 +TEST_F(RefreshRateSelectorTest, getBestRefreshRate_withCloseRefreshRates) { + constexpr int kMinRefreshRate = 10; + constexpr int kMaxRefreshRate = 240; + + DisplayModes displayModes; + for (int fps = kMinRefreshRate; fps < kMaxRefreshRate; fps++) { + const DisplayModeId modeId(fps); + displayModes.try_emplace(modeId, + createDisplayMode(modeId, + Fps::fromValue(static_cast(fps)))); + } + + const TestableRefreshRateSelector selector(std::move(displayModes), + DisplayModeId(kMinRefreshRate)); + + std::vector layers = {{.weight = 1.f}}; + const auto testRefreshRate = [&](Fps fps, LayerVoteType vote) { + layers[0].desiredRefreshRate = fps; + layers[0].vote = vote; + EXPECT_EQ(fps.getIntValue(), selector.getBestRefreshRate(layers)->getFps().getIntValue()) + << "Failed for " << ftl::enum_string(vote); + }; + + for (int fps = kMinRefreshRate; fps < kMaxRefreshRate; fps++) { + const auto refreshRate = Fps::fromValue(static_cast(fps)); + testRefreshRate(refreshRate, LayerVoteType::Heuristic); + testRefreshRate(refreshRate, LayerVoteType::ExplicitDefault); + testRefreshRate(refreshRate, LayerVoteType::ExplicitExactOrMultiple); + testRefreshRate(refreshRate, LayerVoteType::ExplicitExact); + } +} + +// b/190578904 +TEST_F(RefreshRateSelectorTest, getBestRefreshRate_conflictingVotes) { + constexpr DisplayModeId kActiveModeId{0}; + DisplayModes displayModes = makeModes(createDisplayMode(kActiveModeId, 43_Hz), + createDisplayMode(DisplayModeId(1), 53_Hz), + createDisplayMode(DisplayModeId(2), 55_Hz), + createDisplayMode(DisplayModeId(3), 60_Hz)); + + const RefreshRateSelector::GlobalSignals globalSignals = {.touch = false, .idle = false}; + const TestableRefreshRateSelector selector(std::move(displayModes), kActiveModeId); + + const std::vector layers = { + { + .vote = LayerVoteType::ExplicitDefault, + .desiredRefreshRate = 43_Hz, + .seamlessness = Seamlessness::SeamedAndSeamless, + .weight = 0.41f, + }, + { + .vote = LayerVoteType::ExplicitExactOrMultiple, + .desiredRefreshRate = 53_Hz, + .seamlessness = Seamlessness::SeamedAndSeamless, + .weight = 0.41f, + }, + }; + + EXPECT_EQ(53_Hz, selector.getBestRefreshRate(layers, globalSignals)->getFps()); +} + +TEST_F(RefreshRateSelectorTest, modeComparison) { + EXPECT_LT(kMode60->getFps(), kMode90->getFps()); + EXPECT_GE(kMode60->getFps(), kMode60->getFps()); + EXPECT_GE(kMode90->getFps(), kMode90->getFps()); +} + +TEST_F(RefreshRateSelectorTest, testKernelIdleTimerAction) { + using KernelIdleTimerAction = RefreshRateSelector::KernelIdleTimerAction; + + TestableRefreshRateSelector selector(kModes_60_90, kModeId90); + + EXPECT_EQ(KernelIdleTimerAction::TurnOn, selector.getIdleTimerAction()); + + EXPECT_EQ(SetPolicyResult::Changed, + selector.setDisplayManagerPolicy({kModeId60, {60_Hz, 90_Hz}})); + EXPECT_EQ(KernelIdleTimerAction::TurnOn, selector.getIdleTimerAction()); + + EXPECT_EQ(SetPolicyResult::Changed, + selector.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}})); + EXPECT_EQ(KernelIdleTimerAction::TurnOff, selector.getIdleTimerAction()); + + EXPECT_EQ(SetPolicyResult::Changed, + selector.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}})); + EXPECT_EQ(KernelIdleTimerAction::TurnOff, selector.getIdleTimerAction()); +} + +TEST_F(RefreshRateSelectorTest, testKernelIdleTimerActionFor120Hz) { + using KernelIdleTimerAction = RefreshRateSelector::KernelIdleTimerAction; + + TestableRefreshRateSelector selector(kModes_60_120, kModeId120); + + EXPECT_EQ(SetPolicyResult::Changed, + selector.setDisplayManagerPolicy({kModeId60, {0_Hz, 60_Hz}})); + EXPECT_EQ(KernelIdleTimerAction::TurnOn, selector.getIdleTimerAction()); + + EXPECT_EQ(SetPolicyResult::Changed, + selector.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}})); + EXPECT_EQ(KernelIdleTimerAction::TurnOff, selector.getIdleTimerAction()); + + EXPECT_EQ(SetPolicyResult::Changed, + selector.setDisplayManagerPolicy({kModeId60, {60_Hz, 120_Hz}})); + EXPECT_EQ(KernelIdleTimerAction::TurnOn, selector.getIdleTimerAction()); + + EXPECT_EQ(SetPolicyResult::Changed, + selector.setDisplayManagerPolicy({kModeId120, {120_Hz, 120_Hz}})); + EXPECT_EQ(KernelIdleTimerAction::TurnOff, selector.getIdleTimerAction()); +} + +TEST_F(RefreshRateSelectorTest, getFrameRateDivisor) { + TestableRefreshRateSelector selector(kModes_30_60_72_90_120, kModeId30); + + const auto frameRate = 30_Hz; + Fps displayRefreshRate = selector.getActiveMode().getFps(); + EXPECT_EQ(1, RefreshRateSelector::getFrameRateDivisor(displayRefreshRate, frameRate)); + + selector.setActiveModeId(kModeId60); + displayRefreshRate = selector.getActiveMode().getFps(); + EXPECT_EQ(2, RefreshRateSelector::getFrameRateDivisor(displayRefreshRate, frameRate)); + + selector.setActiveModeId(kModeId72); + displayRefreshRate = selector.getActiveMode().getFps(); + EXPECT_EQ(0, RefreshRateSelector::getFrameRateDivisor(displayRefreshRate, frameRate)); + + selector.setActiveModeId(kModeId90); + displayRefreshRate = selector.getActiveMode().getFps(); + EXPECT_EQ(3, RefreshRateSelector::getFrameRateDivisor(displayRefreshRate, frameRate)); + + selector.setActiveModeId(kModeId120); + displayRefreshRate = selector.getActiveMode().getFps(); + EXPECT_EQ(4, RefreshRateSelector::getFrameRateDivisor(displayRefreshRate, frameRate)); + + selector.setActiveModeId(kModeId90); + displayRefreshRate = selector.getActiveMode().getFps(); + EXPECT_EQ(4, RefreshRateSelector::getFrameRateDivisor(displayRefreshRate, 22.5_Hz)); + + EXPECT_EQ(0, RefreshRateSelector::getFrameRateDivisor(24_Hz, 25_Hz)); + EXPECT_EQ(0, RefreshRateSelector::getFrameRateDivisor(24_Hz, 23.976_Hz)); + EXPECT_EQ(0, RefreshRateSelector::getFrameRateDivisor(30_Hz, 29.97_Hz)); + EXPECT_EQ(0, RefreshRateSelector::getFrameRateDivisor(60_Hz, 59.94_Hz)); +} + +TEST_F(RefreshRateSelectorTest, isFractionalPairOrMultiple) { + EXPECT_TRUE(RefreshRateSelector::isFractionalPairOrMultiple(23.976_Hz, 24_Hz)); + EXPECT_TRUE(RefreshRateSelector::isFractionalPairOrMultiple(24_Hz, 23.976_Hz)); + + EXPECT_TRUE(RefreshRateSelector::isFractionalPairOrMultiple(29.97_Hz, 30_Hz)); + EXPECT_TRUE(RefreshRateSelector::isFractionalPairOrMultiple(30_Hz, 29.97_Hz)); + + EXPECT_TRUE(RefreshRateSelector::isFractionalPairOrMultiple(59.94_Hz, 60_Hz)); + EXPECT_TRUE(RefreshRateSelector::isFractionalPairOrMultiple(60_Hz, 59.94_Hz)); + + EXPECT_TRUE(RefreshRateSelector::isFractionalPairOrMultiple(29.97_Hz, 60_Hz)); + EXPECT_TRUE(RefreshRateSelector::isFractionalPairOrMultiple(60_Hz, 29.97_Hz)); + + EXPECT_TRUE(RefreshRateSelector::isFractionalPairOrMultiple(59.94_Hz, 30_Hz)); + EXPECT_TRUE(RefreshRateSelector::isFractionalPairOrMultiple(30_Hz, 59.94_Hz)); + + const auto refreshRates = {23.976_Hz, 24_Hz, 25_Hz, 29.97_Hz, 30_Hz, 50_Hz, 59.94_Hz, 60_Hz}; + for (auto refreshRate : refreshRates) { + EXPECT_FALSE(RefreshRateSelector::isFractionalPairOrMultiple(refreshRate, refreshRate)); + } + + EXPECT_FALSE(RefreshRateSelector::isFractionalPairOrMultiple(24_Hz, 25_Hz)); + EXPECT_FALSE(RefreshRateSelector::isFractionalPairOrMultiple(23.978_Hz, 25_Hz)); + EXPECT_FALSE(RefreshRateSelector::isFractionalPairOrMultiple(29.97_Hz, 59.94_Hz)); +} + +TEST_F(RefreshRateSelectorTest, getFrameRateOverrides_noLayers) { + RefreshRateSelector selector(kModes_30_60_72_90_120, kModeId120); + + EXPECT_TRUE(selector.getFrameRateOverrides({}, 120_Hz, {}).empty()); +} + +TEST_F(RefreshRateSelectorTest, getFrameRateOverrides_60on120) { + RefreshRateSelector selector(kModes_30_60_72_90_120, kModeId120, + {.enableFrameRateOverride = true}); + + std::vector layers = {{.weight = 1.f}}; + layers[0].name = "Test layer"; + layers[0].ownerUid = 1234; + layers[0].desiredRefreshRate = 60_Hz; + layers[0].vote = LayerVoteType::ExplicitDefault; + + auto frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {}); + EXPECT_EQ(1u, frameRateOverrides.size()); + ASSERT_EQ(1u, frameRateOverrides.count(1234)); + EXPECT_EQ(60_Hz, frameRateOverrides.at(1234)); + + layers[0].vote = LayerVoteType::ExplicitExactOrMultiple; + frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {}); + EXPECT_EQ(1u, frameRateOverrides.size()); + ASSERT_EQ(1u, frameRateOverrides.count(1234)); + EXPECT_EQ(60_Hz, frameRateOverrides.at(1234)); + + layers[0].vote = LayerVoteType::NoVote; + frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {}); + EXPECT_TRUE(frameRateOverrides.empty()); + + layers[0].vote = LayerVoteType::Min; + frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {}); + EXPECT_TRUE(frameRateOverrides.empty()); + + layers[0].vote = LayerVoteType::Max; + frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {}); + EXPECT_TRUE(frameRateOverrides.empty()); + + layers[0].vote = LayerVoteType::Heuristic; + frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {}); + EXPECT_TRUE(frameRateOverrides.empty()); +} + +TEST_F(RefreshRateSelectorTest, getFrameRateOverrides_twoUids) { + RefreshRateSelector selector(kModes_30_60_72_90_120, kModeId120, + {.enableFrameRateOverride = true}); + + std::vector layers = {{.ownerUid = 1234, .weight = 1.f}, + {.ownerUid = 5678, .weight = 1.f}}; + + layers[0].name = "Test layer 1234"; + layers[0].desiredRefreshRate = 60_Hz; + layers[0].vote = LayerVoteType::ExplicitDefault; + + layers[1].name = "Test layer 5678"; + layers[1].desiredRefreshRate = 30_Hz; + layers[1].vote = LayerVoteType::ExplicitDefault; + auto frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {}); + + EXPECT_EQ(2u, frameRateOverrides.size()); + ASSERT_EQ(1u, frameRateOverrides.count(1234)); + EXPECT_EQ(60_Hz, frameRateOverrides.at(1234)); + ASSERT_EQ(1u, frameRateOverrides.count(5678)); + EXPECT_EQ(30_Hz, frameRateOverrides.at(5678)); + + layers[1].vote = LayerVoteType::Heuristic; + frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {}); + EXPECT_EQ(1u, frameRateOverrides.size()); + ASSERT_EQ(1u, frameRateOverrides.count(1234)); + EXPECT_EQ(60_Hz, frameRateOverrides.at(1234)); + + layers[1].ownerUid = 1234; + frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {}); + EXPECT_TRUE(frameRateOverrides.empty()); +} + +TEST_F(RefreshRateSelectorTest, getFrameRateOverrides_touch) { + RefreshRateSelector selector(kModes_30_60_72_90_120, kModeId120, + {.enableFrameRateOverride = true}); + + std::vector layers = {{.ownerUid = 1234, .weight = 1.f}}; + layers[0].name = "Test layer"; + layers[0].desiredRefreshRate = 60_Hz; + layers[0].vote = LayerVoteType::ExplicitDefault; + + auto frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {}); + EXPECT_EQ(1u, frameRateOverrides.size()); + ASSERT_EQ(1u, frameRateOverrides.count(1234)); + EXPECT_EQ(60_Hz, frameRateOverrides.at(1234)); + + frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {.touch = true}); + EXPECT_EQ(1u, frameRateOverrides.size()); + ASSERT_EQ(1u, frameRateOverrides.count(1234)); + EXPECT_EQ(60_Hz, frameRateOverrides.at(1234)); + + layers[0].vote = LayerVoteType::ExplicitExact; + frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {}); + EXPECT_EQ(1u, frameRateOverrides.size()); + ASSERT_EQ(1u, frameRateOverrides.count(1234)); + EXPECT_EQ(60_Hz, frameRateOverrides.at(1234)); + + frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {.touch = true}); + EXPECT_EQ(1u, frameRateOverrides.size()); + ASSERT_EQ(1u, frameRateOverrides.count(1234)); + EXPECT_EQ(60_Hz, frameRateOverrides.at(1234)); + + layers[0].vote = LayerVoteType::ExplicitExactOrMultiple; + frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {}); + EXPECT_EQ(1u, frameRateOverrides.size()); + ASSERT_EQ(1u, frameRateOverrides.count(1234)); + EXPECT_EQ(60_Hz, frameRateOverrides.at(1234)); + + frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {.touch = true}); + EXPECT_TRUE(frameRateOverrides.empty()); +} + +} // namespace +} // namespace android::scheduler diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index 147433b422..066083fffa 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -22,7 +22,7 @@ #include "FakeDisplayInjector.h" #include "Scheduler/EventThread.h" -#include "Scheduler/RefreshRateConfigs.h" +#include "Scheduler/RefreshRateSelector.h" #include "TestableScheduler.h" #include "TestableSurfaceFlinger.h" #include "mock/DisplayHardware/MockDisplayMode.h" @@ -78,12 +78,12 @@ protected: createDisplayMode(kDisplayId3, DisplayModeId(0), 60_Hz); static inline const DisplayModes kDisplay3Modes = makeModes(kDisplay3Mode60); - std::shared_ptr mConfigs = - std::make_shared(makeModes(kDisplay1Mode60), - kDisplay1Mode60->getId()); + std::shared_ptr mSelector = + std::make_shared(makeModes(kDisplay1Mode60), + kDisplay1Mode60->getId()); mock::SchedulerCallback mSchedulerCallback; - TestableScheduler* mScheduler = new TestableScheduler{mConfigs, mSchedulerCallback}; + TestableScheduler* mScheduler = new TestableScheduler{mSelector, mSchedulerCallback}; ConnectionHandle mConnectionHandle; MockEventThread* mEventThread; @@ -196,8 +196,8 @@ TEST_F(SchedulerTest, updateDisplayModes) { sp layer = sp::make(mFlinger.flinger()); ASSERT_EQ(1u, mScheduler->layerHistorySize()); - mScheduler->setRefreshRateConfigs( - std::make_shared(kDisplay1Modes, kDisplay1Mode60->getId())); + mScheduler->setRefreshRateSelector( + std::make_shared(kDisplay1Modes, kDisplay1Mode60->getId())); ASSERT_EQ(0u, mScheduler->getNumActiveLayers()); mScheduler->recordLayerHistory(layer.get(), 0, LayerHistory::LayerUpdateType::Buffer); @@ -247,7 +247,7 @@ TEST_F(SchedulerTest, chooseRefreshRateForContentSelectsMaxRefreshRate) { {.displayId = kDisplayId1}); mScheduler->registerDisplay(display); - mScheduler->setRefreshRateConfigs(display->holdRefreshRateConfigs()); + mScheduler->setRefreshRateSelector(display->holdRefreshRateSelector()); const sp layer = sp::make(mFlinger.flinger()); EXPECT_CALL(*layer, isVisible()).WillOnce(Return(true)); @@ -277,8 +277,8 @@ TEST_F(SchedulerTest, chooseDisplayModesSingleDisplay) { mScheduler->registerDisplay(display); - std::vector layers = - std::vector({{.weight = 1.f}, {.weight = 1.f}}); + std::vector layers = + std::vector({{.weight = 1.f}, {.weight = 1.f}}); mScheduler->setContentRequirements(layers); GlobalSignals globalSignals = {.idle = true}; mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals); @@ -343,8 +343,8 @@ TEST_F(SchedulerTest, chooseDisplayModesMultipleDisplays) { globalSignals)(kDisplayId2, kDisplay2Mode60, globalSignals); - std::vector layers = {{.weight = 1.f}, - {.weight = 1.f}}; + std::vector layers = {{.weight = 1.f}, + {.weight = 1.f}}; mScheduler->setContentRequirements(layers); mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals); diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp index dfcfd912f9..6adcd5259d 100644 --- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp @@ -383,8 +383,8 @@ TEST_P(SetFrameRateTest, SetOnParentActivatesTree) { history.record(parent.get(), 0, 0, LayerHistory::LayerUpdateType::Buffer); history.record(child.get(), 0, 0, LayerHistory::LayerUpdateType::Buffer); - const auto configs = mFlinger.mutableScheduler().refreshRateConfigs(); - const auto summary = history.summarize(*configs, 0); + const auto selectorPtr = mFlinger.mutableScheduler().refreshRateSelector(); + const auto summary = history.summarize(*selectorPtr, 0); ASSERT_EQ(2u, summary.size()); EXPECT_EQ(FRAME_RATE_VOTE1.rate, summary[0].desiredRefreshRate); diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp index 6b7e3533a5..4c25463e6e 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp @@ -42,15 +42,15 @@ public: PrimaryDisplayVariant::setupHwcGetActiveConfigCallExpectations(this); DisplayModes modes = makeModes(kMode60, kMode90, kMode120, kMode90_4K); - auto configs = std::make_shared(modes, kModeId60); + auto selectorPtr = std::make_shared(modes, kModeId60); - setupScheduler(configs); + setupScheduler(selectorPtr); mFlinger.onComposerHalHotplug(PrimaryDisplayVariant::HWC_DISPLAY_ID, Connection::CONNECTED); mFlinger.configureAndCommit(); mDisplay = PrimaryDisplayVariant::makeFakeExistingDisplayInjector(this) - .setDisplayModes(std::move(modes), kModeId60, std::move(configs)) + .setDisplayModes(std::move(modes), kModeId60, std::move(selectorPtr)) .inject(); // isVsyncPeriodSwitchSupported should return true, otherwise the SF's HWC proxy @@ -60,7 +60,7 @@ public: } protected: - void setupScheduler(std::shared_ptr); + void setupScheduler(std::shared_ptr); sp mDisplay; mock::EventThread* mAppEventThread; @@ -80,7 +80,7 @@ protected: }; void DisplayModeSwitchingTest::setupScheduler( - std::shared_ptr configs) { + std::shared_ptr selectorPtr) { auto eventThread = std::make_unique(); mAppEventThread = eventThread.get(); auto sfEventThread = std::make_unique(); @@ -108,7 +108,7 @@ void DisplayModeSwitchingTest::setupScheduler( mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker), std::move(eventThread), std::move(sfEventThread), TestableSurfaceFlinger::SchedulerCallbackImpl::kNoOp, - std::move(configs)); + std::move(selectorPtr)); } TEST_F(DisplayModeSwitchingTest, changeRefreshRate_OnActiveDisplay_WithRefreshRequired) { diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index 26b2b673a2..2814d38b47 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -32,17 +32,19 @@ namespace android::scheduler { class TestableScheduler : public Scheduler, private ICompositor { public: - TestableScheduler(std::shared_ptr configs, ISchedulerCallback& callback) + TestableScheduler(std::shared_ptr selectorPtr, + ISchedulerCallback& callback) : TestableScheduler(std::make_unique(), - std::make_unique(), std::move(configs), + std::make_unique(), std::move(selectorPtr), callback) {} TestableScheduler(std::unique_ptr controller, std::unique_ptr tracker, - std::shared_ptr configs, ISchedulerCallback& callback) + std::shared_ptr selectorPtr, + ISchedulerCallback& callback) : Scheduler(*this, callback, Feature::kContentDetection) { mVsyncSchedule.emplace(VsyncSchedule(std::move(tracker), nullptr, std::move(controller))); - setRefreshRateConfigs(std::move(configs)); + setRefreshRateSelector(std::move(selectorPtr)); ON_CALL(*this, postMessage).WillByDefault([](sp&& handler) { // Execute task to prevent broken promise exception on destruction. @@ -74,7 +76,7 @@ public: return mLayerHistory.mActiveLayerInfos.size() + mLayerHistory.mInactiveLayerInfos.size(); } - auto refreshRateConfigs() { return holdRefreshRateConfigs(); } + auto refreshRateSelector() { return holdRefreshRateSelector(); } size_t getNumActiveLayers() NO_THREAD_SAFETY_ANALYSIS { return mLayerHistory.mActiveLayerInfos.size(); @@ -102,7 +104,7 @@ public: mPolicy.idleTimer = globalSignals.idle ? TimerState::Expired : TimerState::Reset; } - void setContentRequirements(std::vector layers) { + void setContentRequirements(std::vector layers) { std::lock_guard lock(mPolicyLock); mPolicy.contentRequirements = std::move(layers); } diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 89812aad7d..4fd44781e0 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -37,7 +37,7 @@ #include "Layer.h" #include "NativeWindowSurface.h" #include "Scheduler/MessageQueue.h" -#include "Scheduler/RefreshRateConfigs.h" +#include "Scheduler/RefreshRateSelector.h" #include "StartPropertySetThread.h" #include "SurfaceFlinger.h" #include "SurfaceFlingerDefaultFactory.h" @@ -191,10 +191,10 @@ public: static constexpr struct TwoDisplayModes { } kTwoDisplayModes; - using RefreshRateConfigsPtr = std::shared_ptr; + using RefreshRateSelectorPtr = std::shared_ptr; using DisplayModesVariant = - std::variant; + std::variant; void setupScheduler(std::unique_ptr vsyncController, std::unique_ptr vsyncTracker, @@ -203,9 +203,9 @@ public: SchedulerCallbackImpl callbackImpl = SchedulerCallbackImpl::kNoOp, DisplayModesVariant modesVariant = kOneDisplayMode, bool useNiceMock = false) { - RefreshRateConfigsPtr configs; - if (std::holds_alternative(modesVariant)) { - configs = std::move(std::get(modesVariant)); + RefreshRateSelectorPtr selectorPtr; + if (std::holds_alternative(modesVariant)) { + selectorPtr = std::move(std::get(modesVariant)); } else { constexpr DisplayModeId kModeId60{0}; DisplayModes modes = makeModes(mock::createDisplayMode(kModeId60, 60_Hz)); @@ -215,10 +215,10 @@ public: modes.try_emplace(kModeId90, mock::createDisplayMode(kModeId90, 90_Hz)); } - configs = std::make_shared(modes, kModeId60); + selectorPtr = std::make_shared(modes, kModeId60); } - const auto fps = FTL_FAKE_GUARD(kMainThreadContext, configs->getActiveMode().getFps()); + const auto fps = FTL_FAKE_GUARD(kMainThreadContext, selectorPtr->getActiveMode().getFps()); mFlinger->mVsyncConfiguration = mFactory.createVsyncConfiguration(fps); mFlinger->mVsyncModulator = sp::make( mFlinger->mVsyncConfiguration->getCurrentConfigs()); @@ -236,12 +236,12 @@ public: mScheduler = new testing::NiceMock(std::move(vsyncController), std::move(vsyncTracker), - std::move(configs), + std::move(selectorPtr), callback); } else { mScheduler = new scheduler::TestableScheduler(std::move(vsyncController), std::move(vsyncTracker), - std::move(configs), callback); + std::move(selectorPtr), callback); } mFlinger->mAppConnectionHandle = mScheduler->createConnection(std::move(appEventThread)); @@ -757,16 +757,17 @@ public: return mFlinger.mutableDisplays().get(mDisplayToken)->get(); } - // If `configs` is nullptr, the injector creates RefreshRateConfigs from the `modes`. - // Otherwise, it uses `configs`, which the caller must create using the same `modes`. + // If `selectorPtr` is nullptr, the injector creates RefreshRateSelector from the `modes`. + // Otherwise, it uses `selectorPtr`, which the caller must create using the same `modes`. // - // TODO(b/182939859): Once `modes` can be retrieved from RefreshRateConfigs, remove - // the `configs` parameter in favor of an alternative setRefreshRateConfigs API. - auto& setDisplayModes(DisplayModes modes, DisplayModeId activeModeId, - std::shared_ptr configs = nullptr) { + // TODO(b/182939859): Once `modes` can be retrieved from RefreshRateSelector, remove + // the `selectorPtr` parameter in favor of an alternative setRefreshRateSelector API. + auto& setDisplayModes( + DisplayModes modes, DisplayModeId activeModeId, + std::shared_ptr selectorPtr = nullptr) { mDisplayModes = std::move(modes); mCreationArgs.activeModeId = activeModeId; - mCreationArgs.refreshRateConfigs = std::move(configs); + mCreationArgs.refreshRateSelector = std::move(selectorPtr); return *this; } @@ -813,7 +814,7 @@ public: auto& modes = mDisplayModes; auto& activeModeId = mCreationArgs.activeModeId; - if (displayId && !mCreationArgs.refreshRateConfigs) { + if (displayId && !mCreationArgs.refreshRateSelector) { if (const auto physicalId = PhysicalDisplayId::tryCast(*displayId)) { if (modes.empty()) { constexpr DisplayModeId kModeId{0}; @@ -833,8 +834,8 @@ public: activeModeId = kModeId; } - mCreationArgs.refreshRateConfigs = - std::make_shared(modes, activeModeId); + mCreationArgs.refreshRateSelector = + std::make_shared(modes, activeModeId); } } -- cgit v1.2.3-59-g8ed1b