Loading services/surfaceflinger/Layer.cpp +1 −1 Original line number Original line Diff line number Diff line Loading @@ -1123,7 +1123,7 @@ bool Layer::propagateFrameRateForLayerTree(FrameRate parentFrameRate, bool* tran // We return whether this layer ot its children has a vote. We ignore ExactOrMultiple votes for // 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 // the same reason we are allowing touch boost for those layers. See // RefreshRateSelector::rankRefreshRates for details. // RefreshRateSelector::rankFrameRates for details. const auto layerVotedWithDefaultCompatibility = const auto layerVotedWithDefaultCompatibility = frameRate.rate.isValid() && frameRate.type == FrameRateCompatibility::Default; frameRate.rate.isValid() && frameRate.type == FrameRateCompatibility::Default; const auto layerVotedWithNoVote = frameRate.type == FrameRateCompatibility::NoVote; const auto layerVotedWithNoVote = frameRate.type == FrameRateCompatibility::NoVote; Loading services/surfaceflinger/Scheduler/RefreshRateSelector.cpp +268 −148 File changed.Preview size limit exceeded, changes collapsed. Show changes services/surfaceflinger/Scheduler/RefreshRateSelector.h +64 −27 Original line number Original line Diff line number Diff line Loading @@ -24,9 +24,11 @@ #include <ftl/concat.h> #include <ftl/concat.h> #include <ftl/optional.h> #include <ftl/optional.h> #include <ftl/unit.h> #include <gui/DisplayEventReceiver.h> #include <gui/DisplayEventReceiver.h> #include <scheduler/Fps.h> #include <scheduler/Fps.h> #include <scheduler/FrameRateMode.h> #include <scheduler/Seamlessness.h> #include <scheduler/Seamlessness.h> #include "DisplayHardware/DisplayMode.h" #include "DisplayHardware/DisplayMode.h" Loading Loading @@ -58,6 +60,9 @@ public: static constexpr nsecs_t MARGIN_FOR_PERIOD_CALCULATION = static constexpr nsecs_t MARGIN_FOR_PERIOD_CALCULATION = std::chrono::nanoseconds(800us).count(); std::chrono::nanoseconds(800us).count(); // The lowest Render Frame Rate that will ever be selected static constexpr Fps kMinSupportedFrameRate = 20_Hz; class Policy { class Policy { static constexpr int kAllowGroupSwitchingDefault = false; static constexpr int kAllowGroupSwitchingDefault = false; Loading Loading @@ -196,12 +201,12 @@ public: } } }; }; struct ScoredRefreshRate { struct ScoredFrameRate { DisplayModePtr modePtr; FrameRateMode frameRateMode; float score = 0.0f; float score = 0.0f; bool operator==(const ScoredRefreshRate& other) const { bool operator==(const ScoredFrameRate& other) const { return modePtr == other.modePtr && score == other.score; return frameRateMode == other.frameRateMode && score == other.score; } } static bool scoresEqual(float lhs, float rhs) { static bool scoresEqual(float lhs, float rhs) { Loading @@ -210,25 +215,25 @@ public: } } struct DescendingScore { struct DescendingScore { bool operator()(const ScoredRefreshRate& lhs, const ScoredRefreshRate& rhs) const { bool operator()(const ScoredFrameRate& lhs, const ScoredFrameRate& rhs) const { return lhs.score > rhs.score && !scoresEqual(lhs.score, rhs.score); return lhs.score > rhs.score && !scoresEqual(lhs.score, rhs.score); } } }; }; }; }; using RefreshRateRanking = std::vector<ScoredRefreshRate>; using FrameRateRanking = std::vector<ScoredFrameRate>; struct RankedRefreshRates { struct RankedFrameRates { RefreshRateRanking ranking; // Ordered by descending score. FrameRateRanking ranking; // Ordered by descending score. GlobalSignals consideredSignals; GlobalSignals consideredSignals; bool operator==(const RankedRefreshRates& other) const { bool operator==(const RankedFrameRates& other) const { return ranking == other.ranking && consideredSignals == other.consideredSignals; return ranking == other.ranking && consideredSignals == other.consideredSignals; } } }; }; RankedRefreshRates getRankedRefreshRates(const std::vector<LayerRequirement>&, RankedFrameRates getRankedFrameRates(const std::vector<LayerRequirement>&, GlobalSignals) const GlobalSignals) const EXCLUDES(mLock); EXCLUDES(mLock); FpsRange getSupportedRefreshRateRange() const EXCLUDES(mLock) { FpsRange getSupportedRefreshRateRange() const EXCLUDES(mLock) { std::lock_guard lock(mLock); std::lock_guard lock(mLock); Loading Loading @@ -257,9 +262,12 @@ public: // Override the frame rate for an app to a value which is also // Override the frame rate for an app to a value which is also // a display refresh rate // a display refresh rate EnabledForNativeRefreshRates, AppOverrideNativeRefreshRates, // Override the frame rate for an app to any value // Override the frame rate for an app to any value AppOverride, // Override the frame rate for all apps and all values. Enabled, Enabled, ftl_last = Enabled ftl_last = Enabled Loading Loading @@ -291,10 +299,13 @@ public: // Returns whether switching modes (refresh rate or resolution) is possible. // 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 // TODO(b/158780872): Consider HAL support, and skip frame rate detection if the modes only // differ in resolution. // differ in resolution. Once Config::FrameRateOverride::Enabled becomes the default, // we can probably remove canSwitch altogether since all devices will be able // to switch to a frame rate divisor. bool canSwitch() const EXCLUDES(mLock) { bool canSwitch() const EXCLUDES(mLock) { std::lock_guard lock(mLock); std::lock_guard lock(mLock); return mDisplayModes.size() > 1; return mDisplayModes.size() > 1 || mFrameRateOverrideConfig == Config::FrameRateOverride::Enabled; } } // Class to enumerate options around toggling the kernel timer on and off. // Class to enumerate options around toggling the kernel timer on and off. Loading @@ -307,10 +318,14 @@ public: // refresh rates. // refresh rates. KernelIdleTimerAction getIdleTimerAction() const; KernelIdleTimerAction getIdleTimerAction() const; bool supportsFrameRateOverrideByContent() const { bool supportsAppFrameRateOverrideByContent() const { return mFrameRateOverrideConfig != Config::FrameRateOverride::Disabled; return mFrameRateOverrideConfig != Config::FrameRateOverride::Disabled; } } bool supportsFrameRateOverride() const { return mFrameRateOverrideConfig == Config::FrameRateOverride::Enabled; } // Return the display refresh rate divisor to match the layer // 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 // frame rate, or 0 if the display refresh rate is not a multiple of the // layer refresh rate. // layer refresh rate. Loading Loading @@ -387,8 +402,8 @@ private: // See mActiveModeIt for thread safety. // See mActiveModeIt for thread safety. DisplayModeIterator getActiveModeItLocked() const REQUIRES(mLock); DisplayModeIterator getActiveModeItLocked() const REQUIRES(mLock); RankedRefreshRates getRankedRefreshRatesLocked(const std::vector<LayerRequirement>&, RankedFrameRates getRankedFrameRatesLocked(const std::vector<LayerRequirement>& layers, GlobalSignals) const REQUIRES(mLock); GlobalSignals signals) const REQUIRES(mLock); // Returns number of display frames and remainder when dividing the layer refresh period by // Returns number of display frames and remainder when dividing the layer refresh period by // display refresh period. // display refresh period. Loading @@ -404,18 +419,24 @@ private: struct RefreshRateScoreComparator; struct RefreshRateScoreComparator; enum class RefreshRateOrder { Ascending, Descending }; enum class RefreshRateOrder { Ascending, Descending, ftl_last = Descending }; // Only uses the primary range, not the app request range. // Only uses the primary range, not the app request range. RefreshRateRanking rankRefreshRates(std::optional<int> anchorGroupOpt, RefreshRateOrder, FrameRateRanking rankFrameRates( std::optional<DisplayModeId> preferredDisplayModeOpt = std::optional<int> anchorGroupOpt, RefreshRateOrder refreshRateOrder, std::nullopt) const REQUIRES(mLock); std::optional<DisplayModeId> preferredDisplayModeOpt = std::nullopt) const REQUIRES(mLock); const Policy* getCurrentPolicyLocked() const REQUIRES(mLock); const Policy* getCurrentPolicyLocked() const REQUIRES(mLock); bool isPolicyValidLocked(const Policy& policy) 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. // 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); float calculateDistanceScoreFromMax(Fps refreshRate) const REQUIRES(mLock); // calculates a score for a layer. Used to determine the display refresh rate // calculates a score for a layer. Used to determine the display refresh rate // and the frame rate override for certains applications. // and the frame rate override for certains applications. float calculateLayerScoreLocked(const LayerRequirement&, Fps refreshRate, float calculateLayerScoreLocked(const LayerRequirement&, Fps refreshRate, Loading @@ -436,11 +457,27 @@ private: : mIdleTimerCallbacks->platform; : mIdleTimerCallbacks->platform; } } bool isNativeRefreshRate(Fps fps) const REQUIRES(mLock) { LOG_ALWAYS_FATAL_IF(mConfig.enableFrameRateOverride != Config::FrameRateOverride::AppOverrideNativeRefreshRates, "should only be called when " "Config::FrameRateOverride::AppOverrideNativeRefreshRates is used"); return mAppOverrideNativeRefreshRates.contains(fps); } std::vector<FrameRateMode> createFrameRateModes( std::function<bool(const DisplayMode&)>&& filterModes, const FpsRange&) const REQUIRES(mLock); // The display modes of the active display. The DisplayModeIterators below are pointers into // 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 // this container, so must be invalidated whenever the DisplayModes change. The Policy below // is also dependent, so must be reset as well. // is also dependent, so must be reset as well. DisplayModes mDisplayModes GUARDED_BY(mLock); DisplayModes mDisplayModes GUARDED_BY(mLock); // Set of supported display refresh rates for easy lookup // when FrameRateOverride::AppOverrideNativeRefreshRates is in use. ftl::SmallMap<Fps, ftl::Unit, 8, FpsApproxEqual> mAppOverrideNativeRefreshRates; // Written under mLock exclusively from kMainThreadContext, so reads from kMainThreadContext // Written under mLock exclusively from kMainThreadContext, so reads from kMainThreadContext // need not be under mLock. // need not be under mLock. DisplayModeIterator mActiveModeIt GUARDED_BY(mLock) GUARDED_BY(kMainThreadContext); DisplayModeIterator mActiveModeIt GUARDED_BY(mLock) GUARDED_BY(kMainThreadContext); Loading @@ -449,8 +486,8 @@ private: DisplayModeIterator mMaxRefreshRateModeIt GUARDED_BY(mLock); DisplayModeIterator mMaxRefreshRateModeIt GUARDED_BY(mLock); // Display modes that satisfy the Policy's ranges, filtered and sorted by refresh rate. // Display modes that satisfy the Policy's ranges, filtered and sorted by refresh rate. std::vector<DisplayModeIterator> mPrimaryRefreshRates GUARDED_BY(mLock); std::vector<FrameRateMode> mPrimaryFrameRates GUARDED_BY(mLock); std::vector<DisplayModeIterator> mAppRequestRefreshRates GUARDED_BY(mLock); std::vector<FrameRateMode> mAppRequestFrameRates GUARDED_BY(mLock); Policy mDisplayManagerPolicy GUARDED_BY(mLock); Policy mDisplayManagerPolicy GUARDED_BY(mLock); std::optional<Policy> mOverridePolicy GUARDED_BY(mLock); std::optional<Policy> mOverridePolicy GUARDED_BY(mLock); Loading @@ -466,11 +503,11 @@ private: const Config mConfig; const Config mConfig; Config::FrameRateOverride mFrameRateOverrideConfig; Config::FrameRateOverride mFrameRateOverrideConfig; struct GetRankedRefreshRatesCache { struct GetRankedFrameRatesCache { std::pair<std::vector<LayerRequirement>, GlobalSignals> arguments; std::pair<std::vector<LayerRequirement>, GlobalSignals> arguments; RankedRefreshRates result; RankedFrameRates result; }; }; mutable std::optional<GetRankedRefreshRatesCache> mGetRankedRefreshRatesCache GUARDED_BY(mLock); mutable std::optional<GetRankedFrameRatesCache> mGetRankedFrameRatesCache GUARDED_BY(mLock); // Declare mIdleTimer last to ensure its thread joins before the mutex/callbacks are destroyed. // Declare mIdleTimer last to ensure its thread joins before the mutex/callbacks are destroyed. std::mutex mIdleTimerCallbacksMutex; std::mutex mIdleTimerCallbacksMutex; Loading services/surfaceflinger/Scheduler/Scheduler.cpp +14 −11 Original line number Original line Diff line number Diff line Loading @@ -152,7 +152,7 @@ std::unique_ptr<VSyncSource> Scheduler::makePrimaryDispSyncSource( std::optional<Fps> Scheduler::getFrameRateOverride(uid_t uid) const { std::optional<Fps> Scheduler::getFrameRateOverride(uid_t uid) const { const bool supportsFrameRateOverrideByContent = const bool supportsFrameRateOverrideByContent = leaderSelectorPtr()->supportsFrameRateOverrideByContent(); leaderSelectorPtr()->supportsAppFrameRateOverrideByContent(); return mFrameRateOverrideMappings return mFrameRateOverrideMappings .getFrameRateOverrideForUid(uid, supportsFrameRateOverrideByContent); .getFrameRateOverrideForUid(uid, supportsFrameRateOverrideByContent); } } Loading Loading @@ -268,7 +268,7 @@ void Scheduler::onScreenReleased(ConnectionHandle handle) { void Scheduler::onFrameRateOverridesChanged(ConnectionHandle handle, PhysicalDisplayId displayId) { void Scheduler::onFrameRateOverridesChanged(ConnectionHandle handle, PhysicalDisplayId displayId) { const bool supportsFrameRateOverrideByContent = const bool supportsFrameRateOverrideByContent = leaderSelectorPtr()->supportsFrameRateOverrideByContent(); leaderSelectorPtr()->supportsAppFrameRateOverrideByContent(); std::vector<FrameRateOverride> overrides = std::vector<FrameRateOverride> overrides = mFrameRateOverrideMappings.getAllFrameRateOverrides(supportsFrameRateOverrideByContent); mFrameRateOverrideMappings.getAllFrameRateOverrides(supportsFrameRateOverrideByContent); Loading Loading @@ -707,7 +707,7 @@ auto Scheduler::applyPolicy(S Policy::*statePtr, T&& newState) -> GlobalSignals auto Scheduler::chooseDisplayModes() const -> DisplayModeChoiceMap { auto Scheduler::chooseDisplayModes() const -> DisplayModeChoiceMap { ATRACE_CALL(); ATRACE_CALL(); using RankedRefreshRates = RefreshRateSelector::RankedRefreshRates; using RankedRefreshRates = RefreshRateSelector::RankedFrameRates; display::PhysicalDisplayVector<RankedRefreshRates> perDisplayRanking; display::PhysicalDisplayVector<RankedRefreshRates> perDisplayRanking; // Tallies the score of a refresh rate across `displayCount` displays. // Tallies the score of a refresh rate across `displayCount` displays. Loading @@ -726,9 +726,10 @@ auto Scheduler::chooseDisplayModes() const -> DisplayModeChoiceMap { for (const auto& [id, selectorPtr] : mRefreshRateSelectors) { for (const auto& [id, selectorPtr] : mRefreshRateSelectors) { auto rankedRefreshRates = auto rankedRefreshRates = selectorPtr->getRankedRefreshRates(mPolicy.contentRequirements, globalSignals); selectorPtr->getRankedFrameRates(mPolicy.contentRequirements, globalSignals); for (const auto& [modePtr, score] : rankedRefreshRates.ranking) { for (const auto& [frameRateMode, score] : rankedRefreshRates.ranking) { const auto& modePtr = frameRateMode.modePtr; const auto [it, inserted] = refreshRateTallies.try_emplace(modePtr->getFps(), score); const auto [it, inserted] = refreshRateTallies.try_emplace(modePtr->getFps(), score); if (!inserted) { if (!inserted) { Loading Loading @@ -771,16 +772,18 @@ auto Scheduler::chooseDisplayModes() const -> DisplayModeChoiceMap { for (auto& [ranking, signals] : perDisplayRanking) { for (auto& [ranking, signals] : perDisplayRanking) { if (!chosenFps) { if (!chosenFps) { auto& [modePtr, _] = ranking.front(); const auto& [frameRateMode, _] = ranking.front(); const auto& modePtr = frameRateMode.modePtr; modeChoices.try_emplace(modePtr->getPhysicalDisplayId(), modeChoices.try_emplace(modePtr->getPhysicalDisplayId(), DisplayModeChoice{std::move(modePtr), signals}); DisplayModeChoice{modePtr, signals}); continue; continue; } } for (auto& [modePtr, _] : ranking) { for (auto& [frameRateMode, _] : ranking) { const auto& modePtr = frameRateMode.modePtr; if (modePtr->getFps() == *chosenFps) { if (modePtr->getFps() == *chosenFps) { modeChoices.try_emplace(modePtr->getPhysicalDisplayId(), modeChoices.try_emplace(modePtr->getPhysicalDisplayId(), DisplayModeChoice{std::move(modePtr), signals}); DisplayModeChoice{modePtr, signals}); break; break; } } } } Loading @@ -804,10 +807,10 @@ DisplayModePtr Scheduler::getPreferredDisplayMode() { if (mPolicy.mode) { if (mPolicy.mode) { const auto ranking = const auto ranking = leaderSelectorPtr() leaderSelectorPtr() ->getRankedRefreshRates(mPolicy.contentRequirements, makeGlobalSignals()) ->getRankedFrameRates(mPolicy.contentRequirements, makeGlobalSignals()) .ranking; .ranking; mPolicy.mode = ranking.front().modePtr; mPolicy.mode = ranking.front().frameRateMode.modePtr; } } return mPolicy.mode; return mPolicy.mode; } } Loading services/surfaceflinger/Scheduler/include/scheduler/Fps.h +13 −0 Original line number Original line Diff line number Diff line Loading @@ -66,6 +66,7 @@ struct FpsRange { Fps max = Fps::fromValue(std::numeric_limits<float>::max()); Fps max = Fps::fromValue(std::numeric_limits<float>::max()); bool includes(Fps) const; bool includes(Fps) const; bool includes(FpsRange) const; }; }; struct FpsRanges { struct FpsRanges { Loading @@ -75,6 +76,8 @@ struct FpsRanges { // the range of frame rates that refers to the render rate, which is // the range of frame rates that refers to the render rate, which is // the rate that frames are swapped. // the rate that frames are swapped. FpsRange render; FpsRange render; bool valid() const; }; }; static_assert(std::is_trivially_copyable_v<Fps>); static_assert(std::is_trivially_copyable_v<Fps>); Loading Loading @@ -159,6 +162,16 @@ inline bool FpsRange::includes(Fps fps) const { return min <= fps && fps <= max; return min <= fps && fps <= max; } } inline bool FpsRange::includes(FpsRange range) const { using namespace fps_approx_ops; return min <= range.min && max >= range.max; } inline bool FpsRanges::valid() const { using fps_approx_ops::operator>=; return physical.max >= render.max; } struct FpsApproxEqual { struct FpsApproxEqual { bool operator()(Fps lhs, Fps rhs) const { return isApproxEqual(lhs, rhs); } bool operator()(Fps lhs, Fps rhs) const { return isApproxEqual(lhs, rhs); } }; }; Loading Loading
services/surfaceflinger/Layer.cpp +1 −1 Original line number Original line Diff line number Diff line Loading @@ -1123,7 +1123,7 @@ bool Layer::propagateFrameRateForLayerTree(FrameRate parentFrameRate, bool* tran // We return whether this layer ot its children has a vote. We ignore ExactOrMultiple votes for // 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 // the same reason we are allowing touch boost for those layers. See // RefreshRateSelector::rankRefreshRates for details. // RefreshRateSelector::rankFrameRates for details. const auto layerVotedWithDefaultCompatibility = const auto layerVotedWithDefaultCompatibility = frameRate.rate.isValid() && frameRate.type == FrameRateCompatibility::Default; frameRate.rate.isValid() && frameRate.type == FrameRateCompatibility::Default; const auto layerVotedWithNoVote = frameRate.type == FrameRateCompatibility::NoVote; const auto layerVotedWithNoVote = frameRate.type == FrameRateCompatibility::NoVote; Loading
services/surfaceflinger/Scheduler/RefreshRateSelector.cpp +268 −148 File changed.Preview size limit exceeded, changes collapsed. Show changes
services/surfaceflinger/Scheduler/RefreshRateSelector.h +64 −27 Original line number Original line Diff line number Diff line Loading @@ -24,9 +24,11 @@ #include <ftl/concat.h> #include <ftl/concat.h> #include <ftl/optional.h> #include <ftl/optional.h> #include <ftl/unit.h> #include <gui/DisplayEventReceiver.h> #include <gui/DisplayEventReceiver.h> #include <scheduler/Fps.h> #include <scheduler/Fps.h> #include <scheduler/FrameRateMode.h> #include <scheduler/Seamlessness.h> #include <scheduler/Seamlessness.h> #include "DisplayHardware/DisplayMode.h" #include "DisplayHardware/DisplayMode.h" Loading Loading @@ -58,6 +60,9 @@ public: static constexpr nsecs_t MARGIN_FOR_PERIOD_CALCULATION = static constexpr nsecs_t MARGIN_FOR_PERIOD_CALCULATION = std::chrono::nanoseconds(800us).count(); std::chrono::nanoseconds(800us).count(); // The lowest Render Frame Rate that will ever be selected static constexpr Fps kMinSupportedFrameRate = 20_Hz; class Policy { class Policy { static constexpr int kAllowGroupSwitchingDefault = false; static constexpr int kAllowGroupSwitchingDefault = false; Loading Loading @@ -196,12 +201,12 @@ public: } } }; }; struct ScoredRefreshRate { struct ScoredFrameRate { DisplayModePtr modePtr; FrameRateMode frameRateMode; float score = 0.0f; float score = 0.0f; bool operator==(const ScoredRefreshRate& other) const { bool operator==(const ScoredFrameRate& other) const { return modePtr == other.modePtr && score == other.score; return frameRateMode == other.frameRateMode && score == other.score; } } static bool scoresEqual(float lhs, float rhs) { static bool scoresEqual(float lhs, float rhs) { Loading @@ -210,25 +215,25 @@ public: } } struct DescendingScore { struct DescendingScore { bool operator()(const ScoredRefreshRate& lhs, const ScoredRefreshRate& rhs) const { bool operator()(const ScoredFrameRate& lhs, const ScoredFrameRate& rhs) const { return lhs.score > rhs.score && !scoresEqual(lhs.score, rhs.score); return lhs.score > rhs.score && !scoresEqual(lhs.score, rhs.score); } } }; }; }; }; using RefreshRateRanking = std::vector<ScoredRefreshRate>; using FrameRateRanking = std::vector<ScoredFrameRate>; struct RankedRefreshRates { struct RankedFrameRates { RefreshRateRanking ranking; // Ordered by descending score. FrameRateRanking ranking; // Ordered by descending score. GlobalSignals consideredSignals; GlobalSignals consideredSignals; bool operator==(const RankedRefreshRates& other) const { bool operator==(const RankedFrameRates& other) const { return ranking == other.ranking && consideredSignals == other.consideredSignals; return ranking == other.ranking && consideredSignals == other.consideredSignals; } } }; }; RankedRefreshRates getRankedRefreshRates(const std::vector<LayerRequirement>&, RankedFrameRates getRankedFrameRates(const std::vector<LayerRequirement>&, GlobalSignals) const GlobalSignals) const EXCLUDES(mLock); EXCLUDES(mLock); FpsRange getSupportedRefreshRateRange() const EXCLUDES(mLock) { FpsRange getSupportedRefreshRateRange() const EXCLUDES(mLock) { std::lock_guard lock(mLock); std::lock_guard lock(mLock); Loading Loading @@ -257,9 +262,12 @@ public: // Override the frame rate for an app to a value which is also // Override the frame rate for an app to a value which is also // a display refresh rate // a display refresh rate EnabledForNativeRefreshRates, AppOverrideNativeRefreshRates, // Override the frame rate for an app to any value // Override the frame rate for an app to any value AppOverride, // Override the frame rate for all apps and all values. Enabled, Enabled, ftl_last = Enabled ftl_last = Enabled Loading Loading @@ -291,10 +299,13 @@ public: // Returns whether switching modes (refresh rate or resolution) is possible. // 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 // TODO(b/158780872): Consider HAL support, and skip frame rate detection if the modes only // differ in resolution. // differ in resolution. Once Config::FrameRateOverride::Enabled becomes the default, // we can probably remove canSwitch altogether since all devices will be able // to switch to a frame rate divisor. bool canSwitch() const EXCLUDES(mLock) { bool canSwitch() const EXCLUDES(mLock) { std::lock_guard lock(mLock); std::lock_guard lock(mLock); return mDisplayModes.size() > 1; return mDisplayModes.size() > 1 || mFrameRateOverrideConfig == Config::FrameRateOverride::Enabled; } } // Class to enumerate options around toggling the kernel timer on and off. // Class to enumerate options around toggling the kernel timer on and off. Loading @@ -307,10 +318,14 @@ public: // refresh rates. // refresh rates. KernelIdleTimerAction getIdleTimerAction() const; KernelIdleTimerAction getIdleTimerAction() const; bool supportsFrameRateOverrideByContent() const { bool supportsAppFrameRateOverrideByContent() const { return mFrameRateOverrideConfig != Config::FrameRateOverride::Disabled; return mFrameRateOverrideConfig != Config::FrameRateOverride::Disabled; } } bool supportsFrameRateOverride() const { return mFrameRateOverrideConfig == Config::FrameRateOverride::Enabled; } // Return the display refresh rate divisor to match the layer // 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 // frame rate, or 0 if the display refresh rate is not a multiple of the // layer refresh rate. // layer refresh rate. Loading Loading @@ -387,8 +402,8 @@ private: // See mActiveModeIt for thread safety. // See mActiveModeIt for thread safety. DisplayModeIterator getActiveModeItLocked() const REQUIRES(mLock); DisplayModeIterator getActiveModeItLocked() const REQUIRES(mLock); RankedRefreshRates getRankedRefreshRatesLocked(const std::vector<LayerRequirement>&, RankedFrameRates getRankedFrameRatesLocked(const std::vector<LayerRequirement>& layers, GlobalSignals) const REQUIRES(mLock); GlobalSignals signals) const REQUIRES(mLock); // Returns number of display frames and remainder when dividing the layer refresh period by // Returns number of display frames and remainder when dividing the layer refresh period by // display refresh period. // display refresh period. Loading @@ -404,18 +419,24 @@ private: struct RefreshRateScoreComparator; struct RefreshRateScoreComparator; enum class RefreshRateOrder { Ascending, Descending }; enum class RefreshRateOrder { Ascending, Descending, ftl_last = Descending }; // Only uses the primary range, not the app request range. // Only uses the primary range, not the app request range. RefreshRateRanking rankRefreshRates(std::optional<int> anchorGroupOpt, RefreshRateOrder, FrameRateRanking rankFrameRates( std::optional<DisplayModeId> preferredDisplayModeOpt = std::optional<int> anchorGroupOpt, RefreshRateOrder refreshRateOrder, std::nullopt) const REQUIRES(mLock); std::optional<DisplayModeId> preferredDisplayModeOpt = std::nullopt) const REQUIRES(mLock); const Policy* getCurrentPolicyLocked() const REQUIRES(mLock); const Policy* getCurrentPolicyLocked() const REQUIRES(mLock); bool isPolicyValidLocked(const Policy& policy) 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. // 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); float calculateDistanceScoreFromMax(Fps refreshRate) const REQUIRES(mLock); // calculates a score for a layer. Used to determine the display refresh rate // calculates a score for a layer. Used to determine the display refresh rate // and the frame rate override for certains applications. // and the frame rate override for certains applications. float calculateLayerScoreLocked(const LayerRequirement&, Fps refreshRate, float calculateLayerScoreLocked(const LayerRequirement&, Fps refreshRate, Loading @@ -436,11 +457,27 @@ private: : mIdleTimerCallbacks->platform; : mIdleTimerCallbacks->platform; } } bool isNativeRefreshRate(Fps fps) const REQUIRES(mLock) { LOG_ALWAYS_FATAL_IF(mConfig.enableFrameRateOverride != Config::FrameRateOverride::AppOverrideNativeRefreshRates, "should only be called when " "Config::FrameRateOverride::AppOverrideNativeRefreshRates is used"); return mAppOverrideNativeRefreshRates.contains(fps); } std::vector<FrameRateMode> createFrameRateModes( std::function<bool(const DisplayMode&)>&& filterModes, const FpsRange&) const REQUIRES(mLock); // The display modes of the active display. The DisplayModeIterators below are pointers into // 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 // this container, so must be invalidated whenever the DisplayModes change. The Policy below // is also dependent, so must be reset as well. // is also dependent, so must be reset as well. DisplayModes mDisplayModes GUARDED_BY(mLock); DisplayModes mDisplayModes GUARDED_BY(mLock); // Set of supported display refresh rates for easy lookup // when FrameRateOverride::AppOverrideNativeRefreshRates is in use. ftl::SmallMap<Fps, ftl::Unit, 8, FpsApproxEqual> mAppOverrideNativeRefreshRates; // Written under mLock exclusively from kMainThreadContext, so reads from kMainThreadContext // Written under mLock exclusively from kMainThreadContext, so reads from kMainThreadContext // need not be under mLock. // need not be under mLock. DisplayModeIterator mActiveModeIt GUARDED_BY(mLock) GUARDED_BY(kMainThreadContext); DisplayModeIterator mActiveModeIt GUARDED_BY(mLock) GUARDED_BY(kMainThreadContext); Loading @@ -449,8 +486,8 @@ private: DisplayModeIterator mMaxRefreshRateModeIt GUARDED_BY(mLock); DisplayModeIterator mMaxRefreshRateModeIt GUARDED_BY(mLock); // Display modes that satisfy the Policy's ranges, filtered and sorted by refresh rate. // Display modes that satisfy the Policy's ranges, filtered and sorted by refresh rate. std::vector<DisplayModeIterator> mPrimaryRefreshRates GUARDED_BY(mLock); std::vector<FrameRateMode> mPrimaryFrameRates GUARDED_BY(mLock); std::vector<DisplayModeIterator> mAppRequestRefreshRates GUARDED_BY(mLock); std::vector<FrameRateMode> mAppRequestFrameRates GUARDED_BY(mLock); Policy mDisplayManagerPolicy GUARDED_BY(mLock); Policy mDisplayManagerPolicy GUARDED_BY(mLock); std::optional<Policy> mOverridePolicy GUARDED_BY(mLock); std::optional<Policy> mOverridePolicy GUARDED_BY(mLock); Loading @@ -466,11 +503,11 @@ private: const Config mConfig; const Config mConfig; Config::FrameRateOverride mFrameRateOverrideConfig; Config::FrameRateOverride mFrameRateOverrideConfig; struct GetRankedRefreshRatesCache { struct GetRankedFrameRatesCache { std::pair<std::vector<LayerRequirement>, GlobalSignals> arguments; std::pair<std::vector<LayerRequirement>, GlobalSignals> arguments; RankedRefreshRates result; RankedFrameRates result; }; }; mutable std::optional<GetRankedRefreshRatesCache> mGetRankedRefreshRatesCache GUARDED_BY(mLock); mutable std::optional<GetRankedFrameRatesCache> mGetRankedFrameRatesCache GUARDED_BY(mLock); // Declare mIdleTimer last to ensure its thread joins before the mutex/callbacks are destroyed. // Declare mIdleTimer last to ensure its thread joins before the mutex/callbacks are destroyed. std::mutex mIdleTimerCallbacksMutex; std::mutex mIdleTimerCallbacksMutex; Loading
services/surfaceflinger/Scheduler/Scheduler.cpp +14 −11 Original line number Original line Diff line number Diff line Loading @@ -152,7 +152,7 @@ std::unique_ptr<VSyncSource> Scheduler::makePrimaryDispSyncSource( std::optional<Fps> Scheduler::getFrameRateOverride(uid_t uid) const { std::optional<Fps> Scheduler::getFrameRateOverride(uid_t uid) const { const bool supportsFrameRateOverrideByContent = const bool supportsFrameRateOverrideByContent = leaderSelectorPtr()->supportsFrameRateOverrideByContent(); leaderSelectorPtr()->supportsAppFrameRateOverrideByContent(); return mFrameRateOverrideMappings return mFrameRateOverrideMappings .getFrameRateOverrideForUid(uid, supportsFrameRateOverrideByContent); .getFrameRateOverrideForUid(uid, supportsFrameRateOverrideByContent); } } Loading Loading @@ -268,7 +268,7 @@ void Scheduler::onScreenReleased(ConnectionHandle handle) { void Scheduler::onFrameRateOverridesChanged(ConnectionHandle handle, PhysicalDisplayId displayId) { void Scheduler::onFrameRateOverridesChanged(ConnectionHandle handle, PhysicalDisplayId displayId) { const bool supportsFrameRateOverrideByContent = const bool supportsFrameRateOverrideByContent = leaderSelectorPtr()->supportsFrameRateOverrideByContent(); leaderSelectorPtr()->supportsAppFrameRateOverrideByContent(); std::vector<FrameRateOverride> overrides = std::vector<FrameRateOverride> overrides = mFrameRateOverrideMappings.getAllFrameRateOverrides(supportsFrameRateOverrideByContent); mFrameRateOverrideMappings.getAllFrameRateOverrides(supportsFrameRateOverrideByContent); Loading Loading @@ -707,7 +707,7 @@ auto Scheduler::applyPolicy(S Policy::*statePtr, T&& newState) -> GlobalSignals auto Scheduler::chooseDisplayModes() const -> DisplayModeChoiceMap { auto Scheduler::chooseDisplayModes() const -> DisplayModeChoiceMap { ATRACE_CALL(); ATRACE_CALL(); using RankedRefreshRates = RefreshRateSelector::RankedRefreshRates; using RankedRefreshRates = RefreshRateSelector::RankedFrameRates; display::PhysicalDisplayVector<RankedRefreshRates> perDisplayRanking; display::PhysicalDisplayVector<RankedRefreshRates> perDisplayRanking; // Tallies the score of a refresh rate across `displayCount` displays. // Tallies the score of a refresh rate across `displayCount` displays. Loading @@ -726,9 +726,10 @@ auto Scheduler::chooseDisplayModes() const -> DisplayModeChoiceMap { for (const auto& [id, selectorPtr] : mRefreshRateSelectors) { for (const auto& [id, selectorPtr] : mRefreshRateSelectors) { auto rankedRefreshRates = auto rankedRefreshRates = selectorPtr->getRankedRefreshRates(mPolicy.contentRequirements, globalSignals); selectorPtr->getRankedFrameRates(mPolicy.contentRequirements, globalSignals); for (const auto& [modePtr, score] : rankedRefreshRates.ranking) { for (const auto& [frameRateMode, score] : rankedRefreshRates.ranking) { const auto& modePtr = frameRateMode.modePtr; const auto [it, inserted] = refreshRateTallies.try_emplace(modePtr->getFps(), score); const auto [it, inserted] = refreshRateTallies.try_emplace(modePtr->getFps(), score); if (!inserted) { if (!inserted) { Loading Loading @@ -771,16 +772,18 @@ auto Scheduler::chooseDisplayModes() const -> DisplayModeChoiceMap { for (auto& [ranking, signals] : perDisplayRanking) { for (auto& [ranking, signals] : perDisplayRanking) { if (!chosenFps) { if (!chosenFps) { auto& [modePtr, _] = ranking.front(); const auto& [frameRateMode, _] = ranking.front(); const auto& modePtr = frameRateMode.modePtr; modeChoices.try_emplace(modePtr->getPhysicalDisplayId(), modeChoices.try_emplace(modePtr->getPhysicalDisplayId(), DisplayModeChoice{std::move(modePtr), signals}); DisplayModeChoice{modePtr, signals}); continue; continue; } } for (auto& [modePtr, _] : ranking) { for (auto& [frameRateMode, _] : ranking) { const auto& modePtr = frameRateMode.modePtr; if (modePtr->getFps() == *chosenFps) { if (modePtr->getFps() == *chosenFps) { modeChoices.try_emplace(modePtr->getPhysicalDisplayId(), modeChoices.try_emplace(modePtr->getPhysicalDisplayId(), DisplayModeChoice{std::move(modePtr), signals}); DisplayModeChoice{modePtr, signals}); break; break; } } } } Loading @@ -804,10 +807,10 @@ DisplayModePtr Scheduler::getPreferredDisplayMode() { if (mPolicy.mode) { if (mPolicy.mode) { const auto ranking = const auto ranking = leaderSelectorPtr() leaderSelectorPtr() ->getRankedRefreshRates(mPolicy.contentRequirements, makeGlobalSignals()) ->getRankedFrameRates(mPolicy.contentRequirements, makeGlobalSignals()) .ranking; .ranking; mPolicy.mode = ranking.front().modePtr; mPolicy.mode = ranking.front().frameRateMode.modePtr; } } return mPolicy.mode; return mPolicy.mode; } } Loading
services/surfaceflinger/Scheduler/include/scheduler/Fps.h +13 −0 Original line number Original line Diff line number Diff line Loading @@ -66,6 +66,7 @@ struct FpsRange { Fps max = Fps::fromValue(std::numeric_limits<float>::max()); Fps max = Fps::fromValue(std::numeric_limits<float>::max()); bool includes(Fps) const; bool includes(Fps) const; bool includes(FpsRange) const; }; }; struct FpsRanges { struct FpsRanges { Loading @@ -75,6 +76,8 @@ struct FpsRanges { // the range of frame rates that refers to the render rate, which is // the range of frame rates that refers to the render rate, which is // the rate that frames are swapped. // the rate that frames are swapped. FpsRange render; FpsRange render; bool valid() const; }; }; static_assert(std::is_trivially_copyable_v<Fps>); static_assert(std::is_trivially_copyable_v<Fps>); Loading Loading @@ -159,6 +162,16 @@ inline bool FpsRange::includes(Fps fps) const { return min <= fps && fps <= max; return min <= fps && fps <= max; } } inline bool FpsRange::includes(FpsRange range) const { using namespace fps_approx_ops; return min <= range.min && max >= range.max; } inline bool FpsRanges::valid() const { using fps_approx_ops::operator>=; return physical.max >= render.max; } struct FpsApproxEqual { struct FpsApproxEqual { bool operator()(Fps lhs, Fps rhs) const { return isApproxEqual(lhs, rhs); } bool operator()(Fps lhs, Fps rhs) const { return isApproxEqual(lhs, rhs); } }; }; Loading