diff options
Diffstat (limited to 'services/surfaceflinger/Scheduler/RefreshRateConfigs.h')
-rw-r--r-- | services/surfaceflinger/Scheduler/RefreshRateConfigs.h | 298 |
1 files changed, 194 insertions, 104 deletions
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index 27bf0ecf9f..dfd13953e7 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -17,15 +17,18 @@ #pragma once #include <android-base/stringprintf.h> +#include <gui/DisplayEventReceiver.h> #include <algorithm> #include <numeric> #include <optional> #include <type_traits> +#include "DisplayHardware/DisplayMode.h" #include "DisplayHardware/HWComposer.h" -#include "HwcStrongTypes.h" +#include "Fps.h" #include "Scheduler/SchedulerUtils.h" +#include "Scheduler/Seamlessness.h" #include "Scheduler/StrongTyping.h" namespace android::scheduler { @@ -39,6 +42,8 @@ inline RefreshRateConfigEvent operator|(RefreshRateConfigEvent lhs, RefreshRateC return static_cast<RefreshRateConfigEvent>(static_cast<T>(lhs) | static_cast<T>(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 @@ -48,7 +53,7 @@ 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(); + std::chrono::nanoseconds(800us).count(); class RefreshRate { private: @@ -59,99 +64,114 @@ public: }; public: - RefreshRate(HwcConfigIndexType configId, - std::shared_ptr<const HWC2::Display::Config> config, std::string name, - float fps, ConstructorTag) - : configId(configId), hwcConfig(config), name(std::move(name)), fps(fps) {} - - RefreshRate(const RefreshRate&) = delete; + RefreshRate(DisplayModeId modeId, DisplayModePtr mode, Fps fps, ConstructorTag) + : modeId(modeId), mode(mode), fps(std::move(fps)) {} - HwcConfigIndexType getConfigId() const { return configId; } - nsecs_t getVsyncPeriod() const { return hwcConfig->getVsyncPeriod(); } - int32_t getConfigGroup() const { return hwcConfig->getConfigGroup(); } - const std::string& getName() const { return name; } - float getFps() const { return fps; } + DisplayModeId getModeId() const { return modeId; } + nsecs_t getVsyncPeriod() const { return mode->getVsyncPeriod(); } + int32_t getModeGroup() const { return mode->getGroup(); } + std::string getName() const { return to_string(fps); } + Fps getFps() const { return fps; } // Checks whether the fps of this RefreshRate struct is within a given min and max refresh - // rate passed in. FPS_EPSILON is applied to the boundaries for approximation. - bool inPolicy(float minRefreshRate, float maxRefreshRate) const { - return (fps >= (minRefreshRate - FPS_EPSILON) && fps <= (maxRefreshRate + FPS_EPSILON)); + // rate passed in. Margin of error is applied to the boundaries for approximation. + bool inPolicy(Fps minRefreshRate, Fps maxRefreshRate) const { + return minRefreshRate.lessThanOrEqualWithMargin(fps) && + fps.lessThanOrEqualWithMargin(maxRefreshRate); } bool operator!=(const RefreshRate& other) const { - return configId != other.configId || hwcConfig != other.hwcConfig; + return modeId != other.modeId || mode != other.mode; } - bool operator<(const RefreshRate& other) const { return getFps() < other.getFps(); } + bool operator<(const RefreshRate& other) const { + return getFps().getValue() < other.getFps().getValue(); + } bool operator==(const RefreshRate& other) const { return !(*this != other); } + std::string toString() const; + friend std::ostream& operator<<(std::ostream& os, const RefreshRate& refreshRate) { + return os << refreshRate.toString(); + } + private: friend RefreshRateConfigs; friend class RefreshRateConfigsTest; - // The tolerance within which we consider FPS approximately equals. - static constexpr float FPS_EPSILON = 0.001f; - - // This config ID corresponds to the position of the config in the vector that is stored - // on the device. - const HwcConfigIndexType configId; - // The config itself - std::shared_ptr<const HWC2::Display::Config> hwcConfig; - // Human readable name of the refresh rate. - const std::string name; + const DisplayModeId modeId; + DisplayModePtr mode; // Refresh rate in frames per second - const float fps = 0; + const Fps fps{0.0f}; }; using AllRefreshRatesMapType = - std::unordered_map<HwcConfigIndexType, std::unique_ptr<const RefreshRate>>; + std::unordered_map<DisplayModeId, std::unique_ptr<const RefreshRate>>; - struct Policy { - struct Range { - float min = 0; - float max = std::numeric_limits<float>::max(); + struct FpsRange { + Fps min{0.0f}; + Fps max{std::numeric_limits<float>::max()}; - bool operator==(const Range& other) const { - return min == other.min && max == other.max; - } + bool operator==(const FpsRange& other) const { + return min.equalsWithMargin(other.min) && max.equalsWithMargin(other.max); + } - bool operator!=(const Range& other) const { return !(*this == other); } - }; + bool operator!=(const FpsRange& other) const { return !(*this == other); } + + std::string toString() const { + return base::StringPrintf("[%s %s]", to_string(min).c_str(), to_string(max).c_str()); + } + }; - // The default config, used to ensure we only initiate display config switches within the - // same config group as defaultConfigId's group. - HwcConfigIndexType defaultConfig; + struct Policy { + private: + 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 configs we'll consider when switching refresh rates. Unless we get an explicit + // display modes we'll consider when switching refresh rates. Unless we get an explicit // signal from an app, we should stay within this range. - Range primaryRange; - // The app request refresh rate range allows us to consider more display configs when + 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. - Range appRequestRange; - // Whether or not we switch config groups to get the best frame rate. Only used by tests. - bool allowGroupSwitching = false; + FpsRange appRequestRange; Policy() = default; - Policy(HwcConfigIndexType defaultConfig, const Range& range) - : Policy(defaultConfig, range, range) {} - Policy(HwcConfigIndexType defaultConfig, const Range& primaryRange, - const Range& appRequestRange) - : defaultConfig(defaultConfig), + + Policy(DisplayModeId defaultMode, const FpsRange& range) + : Policy(defaultMode, kAllowGroupSwitchingDefault, range, range) {} + + Policy(DisplayModeId defaultMode, bool allowGroupSwitching, const FpsRange& range) + : Policy(defaultMode, allowGroupSwitching, range, range) {} + + Policy(DisplayModeId defaultMode, const FpsRange& primaryRange, + const FpsRange& appRequestRange) + : Policy(defaultMode, kAllowGroupSwitchingDefault, primaryRange, appRequestRange) {} + + Policy(DisplayModeId defaultMode, bool allowGroupSwitching, const FpsRange& primaryRange, + const FpsRange& appRequestRange) + : defaultMode(defaultMode), + allowGroupSwitching(allowGroupSwitching), primaryRange(primaryRange), appRequestRange(appRequestRange) {} bool operator==(const Policy& other) const { - return defaultConfig == other.defaultConfig && primaryRange == other.primaryRange && + 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; }; // Return code set*Policy() to indicate the current policy is unchanged. @@ -177,8 +197,8 @@ public: // Gets the display manager policy, regardless of whether an override policy is active. Policy getDisplayManagerPolicy() const EXCLUDES(mLock); - // Returns true if config is allowed by the current policy. - bool isConfigAllowed(HwcConfigIndexType config) 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 { @@ -188,8 +208,11 @@ public: 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 + 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 + }; // Captures the layer requirements for a refresh rate. This will be used to determine the @@ -197,10 +220,14 @@ public: struct LayerRequirement { // Layer's name. Used for debugging purposes. std::string name; + // Layer's owner uid + uid_t ownerUid = static_cast<uid_t>(-1); // Layer vote type. LayerVoteType vote = LayerVoteType::NoVote; // Layer's desired refresh rate, if applicable. - float desiredRefreshRate = 0.0f; + Fps desiredRefreshRate{0.0f}; + // 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; @@ -209,23 +236,24 @@ public: bool operator==(const LayerRequirement& other) const { return name == other.name && vote == other.vote && - desiredRefreshRate == other.desiredRefreshRate && weight == other.weight && + desiredRefreshRate.equalsWithMargin(other.desiredRefreshRate) && + seamlessness == other.seamlessness && weight == other.weight && focused == other.focused; } bool operator!=(const LayerRequirement& other) const { return !(*this == other); } }; - // Returns the refresh rate that fits best to the given layers. - const RefreshRate& getRefreshRateForContent(const std::vector<LayerRequirement>& layers) const - EXCLUDES(mLock); - // 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; + + bool operator==(const GlobalSignals& other) const { + return touch == other.touch && idle == other.idle; + } }; // Returns the refresh rate that fits best to the given layers. @@ -233,57 +261,73 @@ public: // globalSignals - global state of touch and idle // outSignalsConsidered - An output param that tells the caller whether the refresh rate was // chosen based on touch boost and/or idle timer. - const RefreshRate& getBestRefreshRate(const std::vector<LayerRequirement>& layers, - const GlobalSignals& globalSignals, - GlobalSignals* outSignalsConsidered = nullptr) const + RefreshRate getBestRefreshRate(const std::vector<LayerRequirement>& layers, + const GlobalSignals& globalSignals, + GlobalSignals* outSignalsConsidered = nullptr) const EXCLUDES(mLock); - // Returns all the refresh rates supported by the device. This won't change at runtime. - const AllRefreshRatesMapType& getAllRefreshRates() const EXCLUDES(mLock); + FpsRange getSupportedRefreshRateRange() const EXCLUDES(mLock) { + std::lock_guard lock(mLock); + return {mMinSupportedRefreshRate->getFps(), mMaxSupportedRefreshRate->getFps()}; + } - // Returns the lowest refresh rate supported by the device. This won't change at runtime. - const RefreshRate& getMinRefreshRate() const { return *mMinSupportedRefreshRate; } - - // 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 RefreshRate& getMinRefreshRateByPolicy() const EXCLUDES(mLock); - - // Returns the highest refresh rate supported by the device. This won't change at runtime. - const RefreshRate& getMaxRefreshRate() const { return *mMaxSupportedRefreshRate; } + std::optional<Fps> onKernelTimerChanged(std::optional<DisplayModeId> desiredActiveModeId, + bool timerExpired) const EXCLUDES(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 RefreshRate& getMaxRefreshRateByPolicy() const EXCLUDES(mLock); + RefreshRate getMaxRefreshRateByPolicy() const EXCLUDES(mLock); // Returns the current refresh rate - const RefreshRate& getCurrentRefreshRate() const EXCLUDES(mLock); + RefreshRate getCurrentRefreshRate() const EXCLUDES(mLock); // Returns the current refresh rate, if allowed. Otherwise the default that is allowed by // the policy. - const RefreshRate& getCurrentRefreshRateByPolicy() const; + RefreshRate getCurrentRefreshRateByPolicy() const; - // Returns the refresh rate that corresponds to a HwcConfigIndexType. This won't change at + // Returns the refresh rate that corresponds to a DisplayModeId. This may change at // runtime. - const RefreshRate& getRefreshRateFromConfigId(HwcConfigIndexType configId) const { - return *mRefreshRates.at(configId); + // TODO(b/159590486) An invalid mode id may be given here if the dipslay modes have changed. + RefreshRate getRefreshRateFromModeId(DisplayModeId modeId) const EXCLUDES(mLock) { + std::lock_guard lock(mLock); + return *mRefreshRates.at(modeId); }; - // Stores the current configId the device operates at - void setCurrentConfigId(HwcConfigIndexType configId) EXCLUDES(mLock); + // Stores the current modeId the device operates at + void setCurrentModeId(DisplayModeId) EXCLUDES(mLock); // Returns a string that represents the layer vote type static std::string layerVoteTypeString(LayerVoteType vote); // Returns a known frame rate that is the closest to frameRate - float findClosestKnownFrameRate(float frameRate) const; + Fps findClosestKnownFrameRate(Fps frameRate) const; + + // 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; + }; + + RefreshRateConfigs(const DisplayModes& modes, DisplayModeId currentModeId, + Config config = {.enableFrameRateOverride = false, + .frameRateMultipleThreshold = 0}); - RefreshRateConfigs(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs, - HwcConfigIndexType currentConfigId); + void updateDisplayModes(const DisplayModes& mode, DisplayModeId currentModeId) EXCLUDES(mLock); - // Class to enumerate options around toggling the kernel timer on and off. We have an option - // for no change to avoid extra calls to kernel. + // 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 mRefreshRates.size() > 1; + } + + // Class to enumerate options around toggling the kernel timer on and off. enum class KernelIdleTimerAction { - NoChange, // Do not change the idle timer. TurnOff, // Turn off the idle timer. TurnOn // Turn on the idle timer. }; @@ -291,16 +335,42 @@ public: // refresh rates. KernelIdleTimerAction getIdleTimerAction() const; + bool supportsFrameRateOverride() const { return mSupportsFrameRateOverride; } + + // Return the display refresh rate divider to match the layer + // frame rate, or 0 if the display refresh rate is not a multiple of the + // layer refresh rate. + static int getFrameRateDivider(Fps displayFrameRate, Fps layerFrameRate); + + using UidToFrameRateOverride = std::map<uid_t, Fps>; + // Returns the frame rate override for each uid. + // + // @param layers list of visible layers + // @param displayFrameRate the display frame rate + // @param touch whether touch timer is active (i.e. user touched the screen recently) + UidToFrameRateOverride getFrameRateOverrides(const std::vector<LayerRequirement>& layers, + Fps displayFrameRate, bool touch) const + EXCLUDES(mLock); + + void dump(std::string& result) const EXCLUDES(mLock); + private: friend class RefreshRateConfigsTest; void constructAvailableRefreshRates() REQUIRES(mLock); - static std::vector<float> constructKnownFrameRates( - const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs); - void getSortedRefreshRateList( + void getSortedRefreshRateListLocked( const std::function<bool(const RefreshRate&)>& shouldAddRefreshRate, - std::vector<const RefreshRate*>* outRefreshRates); + std::vector<const RefreshRate*>* outRefreshRates) REQUIRES(mLock); + + std::optional<RefreshRate> getCachedBestRefreshRate(const std::vector<LayerRequirement>& layers, + const GlobalSignals& globalSignals, + GlobalSignals* outSignalsConsidered) const + REQUIRES(mLock); + + RefreshRate getBestRefreshRateLocked(const std::vector<LayerRequirement>& layers, + const GlobalSignals& globalSignals, + GlobalSignals* outSignalsConsidered) const REQUIRES(mLock); // Returns the refresh rate with the highest score in the collection specified from begin // to end. If there are more than one with the same highest refresh rate, the first one is @@ -325,11 +395,19 @@ private: const RefreshRate& getCurrentRefreshRateByPolicyLocked() const REQUIRES(mLock); const Policy* getCurrentPolicyLocked() const REQUIRES(mLock); - bool isPolicyValid(const Policy& policy); + bool isPolicyValidLocked(const Policy& policy) const REQUIRES(mLock); - // The list of refresh rates, indexed by display config ID. This must not change after this + // Returns whether the layer is allowed to vote for the given refresh rate. + bool isVoteAllowed(const LayerRequirement&, const RefreshRate&) const; + + // 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&, const RefreshRate&, + bool isSeamlessSwitch) const REQUIRES(mLock); + + // The list of refresh rates, indexed by display modes ID. This may change after this // object is initialized. - AllRefreshRatesMapType mRefreshRates; + AllRefreshRatesMapType mRefreshRates GUARDED_BY(mLock); // The list of refresh rates in the primary range of the current policy, ordered by vsyncPeriod // (the first element is the lowest refresh rate). @@ -339,7 +417,7 @@ private: // vsyncPeriod (the first element is the lowest refresh rate). std::vector<const RefreshRate*> mAppRequestRefreshRates GUARDED_BY(mLock); - // The current config. This will change at runtime. This is set by SurfaceFlinger on + // The current display mode. This will change at runtime. This is set by SurfaceFlinger on // the main thread, and read by the Scheduler (and other objects) on other threads. const RefreshRate* mCurrentRefreshRate GUARDED_BY(mLock); @@ -349,15 +427,27 @@ private: std::optional<Policy> mOverridePolicy GUARDED_BY(mLock); // The min and max refresh rates supported by the device. - // This will not change at runtime. - const RefreshRate* mMinSupportedRefreshRate; - const RefreshRate* mMaxSupportedRefreshRate; + // This may change at runtime. + const RefreshRate* mMinSupportedRefreshRate GUARDED_BY(mLock); + const RefreshRate* mMaxSupportedRefreshRate GUARDED_BY(mLock); 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<float> mKnownFrameRates; + const std::vector<Fps> mKnownFrameRates; + + const Config mConfig; + bool mSupportsFrameRateOverride; + + struct GetBestRefreshRateInvocation { + std::vector<LayerRequirement> layerRequirements; + GlobalSignals globalSignals; + GlobalSignals outSignalsConsidered; + RefreshRate resultingBestRefreshRate; + }; + mutable std::optional<GetBestRefreshRateInvocation> lastBestRefreshRateInvocation + GUARDED_BY(mLock); }; } // namespace android::scheduler |