567 lines
22 KiB
C
567 lines
22 KiB
C
|
|
/*
|
||
|
|
* 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 <algorithm>
|
||
|
|
#include <numeric>
|
||
|
|
#include <type_traits>
|
||
|
|
#include <utility>
|
||
|
|
#include <variant>
|
||
|
|
|
||
|
|
#include <ftl/concat.h>
|
||
|
|
#include <ftl/optional.h>
|
||
|
|
#include <ftl/unit.h>
|
||
|
|
#include <gui/DisplayEventReceiver.h>
|
||
|
|
|
||
|
|
#include <scheduler/Fps.h>
|
||
|
|
#include <scheduler/FrameRateMode.h>
|
||
|
|
#include <scheduler/Seamlessness.h>
|
||
|
|
|
||
|
|
#include "DisplayHardware/DisplayMode.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<DisplayModeEvent>;
|
||
|
|
return static_cast<DisplayModeEvent>(static_cast<T>(lhs) | static_cast<T>(rhs));
|
||
|
|
}
|
||
|
|
|
||
|
|
using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride;
|
||
|
|
|
||
|
|
#ifdef MTK_SF_MSYNC_3
|
||
|
|
#define REFRESH_RATE_SET_DEFAULT 1000
|
||
|
|
#define REFRESH_RATE_CONTROL_BY_AP 1001
|
||
|
|
#define REFRESH_RATE_SET_DEFAULT_BY_AP 2000
|
||
|
|
#endif
|
||
|
|
|
||
|
|
// 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();
|
||
|
|
|
||
|
|
// The lowest Render Frame Rate that will ever be selected
|
||
|
|
#ifdef MTK_SF_MSYNC_3
|
||
|
|
static Fps kMinSupportedFrameRate;
|
||
|
|
#else
|
||
|
|
static constexpr Fps kMinSupportedFrameRate = 20_Hz;
|
||
|
|
#endif
|
||
|
|
|
||
|
|
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 ranges. @see DisplayModeSpecs.aidl for details.
|
||
|
|
// TODO(b/257072060): use the render range when selecting SF render rate
|
||
|
|
// or the app override frame rate
|
||
|
|
FpsRanges primaryRanges;
|
||
|
|
// The app request refresh rate ranges. @see DisplayModeSpecs.aidl for details.
|
||
|
|
FpsRanges appRequestRanges;
|
||
|
|
|
||
|
|
Policy() = default;
|
||
|
|
|
||
|
|
Policy(DisplayModeId defaultMode, FpsRange range,
|
||
|
|
bool allowGroupSwitching = kAllowGroupSwitchingDefault)
|
||
|
|
: Policy(defaultMode, FpsRanges{range, range}, FpsRanges{range, range},
|
||
|
|
allowGroupSwitching) {}
|
||
|
|
|
||
|
|
Policy(DisplayModeId defaultMode, FpsRanges primaryRanges, FpsRanges appRequestRanges,
|
||
|
|
bool allowGroupSwitching = kAllowGroupSwitchingDefault)
|
||
|
|
: defaultMode(defaultMode),
|
||
|
|
allowGroupSwitching(allowGroupSwitching),
|
||
|
|
primaryRanges(primaryRanges),
|
||
|
|
appRequestRanges(appRequestRanges) {}
|
||
|
|
|
||
|
|
bool operator==(const Policy& other) const {
|
||
|
|
using namespace fps_approx_ops;
|
||
|
|
return defaultMode == other.defaultMode && primaryRanges == other.primaryRanges &&
|
||
|
|
appRequestRanges == other.appRequestRanges &&
|
||
|
|
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<DisplayManagerPolicy, OverridePolicy, NoOverridePolicy>;
|
||
|
|
|
||
|
|
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(const FrameRateMode&) 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
|
||
|
|
|
||
|
|
#ifdef MTK_SF_MSYNC_3
|
||
|
|
NoChange, // Not change the refresh rate
|
||
|
|
Heuristic_Infrequent, // Heuristic but infrequent
|
||
|
|
ftl_last = Heuristic_Infrequent
|
||
|
|
#else
|
||
|
|
ftl_last = ExplicitExact
|
||
|
|
#endif
|
||
|
|
};
|
||
|
|
|
||
|
|
// 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<uid_t>(-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;
|
||
|
|
#ifdef MTK_SF_MSYNC_3
|
||
|
|
bool isProtected = false;
|
||
|
|
#endif
|
||
|
|
|
||
|
|
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 ScoredFrameRate {
|
||
|
|
FrameRateMode frameRateMode;
|
||
|
|
float score = 0.0f;
|
||
|
|
|
||
|
|
bool operator==(const ScoredFrameRate& other) const {
|
||
|
|
return frameRateMode == other.frameRateMode && 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 ScoredFrameRate& lhs, const ScoredFrameRate& rhs) const {
|
||
|
|
return lhs.score > rhs.score && !scoresEqual(lhs.score, rhs.score);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
};
|
||
|
|
|
||
|
|
using FrameRateRanking = std::vector<ScoredFrameRate>;
|
||
|
|
|
||
|
|
struct RankedFrameRates {
|
||
|
|
FrameRateRanking ranking; // Ordered by descending score.
|
||
|
|
GlobalSignals consideredSignals;
|
||
|
|
|
||
|
|
bool operator==(const RankedFrameRates& other) const {
|
||
|
|
return ranking == other.ranking && consideredSignals == other.consideredSignals;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
RankedFrameRates getRankedFrameRates(const std::vector<LayerRequirement>&, GlobalSignals) const
|
||
|
|
EXCLUDES(mLock);
|
||
|
|
|
||
|
|
FpsRange getSupportedRefreshRateRange() const EXCLUDES(mLock) {
|
||
|
|
std::lock_guard lock(mLock);
|
||
|
|
return {mMinRefreshRateModeIt->second->getFps(), mMaxRefreshRateModeIt->second->getFps()};
|
||
|
|
}
|
||
|
|
|
||
|
|
ftl::Optional<FrameRateMode> onKernelTimerChanged(
|
||
|
|
std::optional<DisplayModeId> desiredActiveModeId, bool timerExpired) const
|
||
|
|
EXCLUDES(mLock);
|
||
|
|
|
||
|
|
void setActiveMode(DisplayModeId, Fps renderFrameRate) EXCLUDES(mLock);
|
||
|
|
|
||
|
|
// See mActiveModeOpt for thread safety.
|
||
|
|
FrameRateMode getActiveMode() const EXCLUDES(mLock);
|
||
|
|
|
||
|
|
// Returns a known frame rate that is the closest to frameRate
|
||
|
|
#ifdef MTK_SF_MSYNC_3
|
||
|
|
Fps findClosestKnownFrameRate(Fps frameRate, bool bCheckDefaultDistance = false) const;
|
||
|
|
#else
|
||
|
|
Fps findClosestKnownFrameRate(Fps frameRate) const;
|
||
|
|
#endif
|
||
|
|
|
||
|
|
enum class KernelIdleTimerController { Sysprop, HwcApi, ftl_last = HwcApi };
|
||
|
|
|
||
|
|
// Configuration flags.
|
||
|
|
struct Config {
|
||
|
|
enum class FrameRateOverride {
|
||
|
|
// Do not override the frame rate for an app
|
||
|
|
Disabled,
|
||
|
|
|
||
|
|
// Override the frame rate for an app to a value which is also
|
||
|
|
// a display refresh rate
|
||
|
|
AppOverrideNativeRefreshRates,
|
||
|
|
|
||
|
|
// Override the frame rate for an app to any value
|
||
|
|
AppOverride,
|
||
|
|
|
||
|
|
// Override the frame rate for all apps and all values.
|
||
|
|
Enabled,
|
||
|
|
|
||
|
|
ftl_last = Enabled
|
||
|
|
};
|
||
|
|
FrameRateOverride enableFrameRateOverride = FrameRateOverride::Disabled;
|
||
|
|
|
||
|
|
// 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.
|
||
|
|
ftl::Optional<KernelIdleTimerController> kernelIdleTimerController;
|
||
|
|
};
|
||
|
|
|
||
|
|
RefreshRateSelector(
|
||
|
|
DisplayModes, DisplayModeId activeModeId,
|
||
|
|
Config config = {.enableFrameRateOverride = Config::FrameRateOverride::Disabled,
|
||
|
|
.frameRateMultipleThreshold = 0,
|
||
|
|
.idleTimerTimeout = 0ms,
|
||
|
|
.kernelIdleTimerController = {}});
|
||
|
|
|
||
|
|
RefreshRateSelector(const RefreshRateSelector&) = delete;
|
||
|
|
RefreshRateSelector& operator=(const RefreshRateSelector&) = delete;
|
||
|
|
|
||
|
|
const DisplayModes& displayModes() const { return mDisplayModes; }
|
||
|
|
|
||
|
|
// 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. 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) {
|
||
|
|
std::lock_guard lock(mLock);
|
||
|
|
return mDisplayModes.size() > 1 ||
|
||
|
|
mFrameRateOverrideConfig == Config::FrameRateOverride::Enabled;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 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 supportsAppFrameRateOverrideByContent() const {
|
||
|
|
return mFrameRateOverrideConfig != Config::FrameRateOverride::Disabled;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool supportsFrameRateOverride() const {
|
||
|
|
return mFrameRateOverrideConfig == Config::FrameRateOverride::Enabled;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 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<uid_t, Fps>;
|
||
|
|
|
||
|
|
// Returns the frame rate override for each uid.
|
||
|
|
UidToFrameRateOverride getFrameRateOverrides(const std::vector<LayerRequirement>&,
|
||
|
|
Fps displayFrameRate, GlobalSignals) const
|
||
|
|
EXCLUDES(mLock);
|
||
|
|
|
||
|
|
std::optional<KernelIdleTimerController> kernelIdleTimerController() {
|
||
|
|
return mConfig.kernelIdleTimerController;
|
||
|
|
}
|
||
|
|
|
||
|
|
struct IdleTimerCallbacks {
|
||
|
|
struct Callbacks {
|
||
|
|
std::function<void()> onReset;
|
||
|
|
std::function<void()> 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();
|
||
|
|
}
|
||
|
|
|
||
|
|
#ifdef MTK_SF_HINT_LOW_POWER
|
||
|
|
void replaceIdleTimer(int64_t millis) {
|
||
|
|
mIdleTimer.emplace(
|
||
|
|
"IdleTimer", std::chrono::milliseconds(millis),
|
||
|
|
[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();
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
void startIdleTimer() {
|
||
|
|
if (mIdleTimer) {
|
||
|
|
mIdleTimer->start();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void stopIdleTimer() {
|
||
|
|
if (mIdleTimer) {
|
||
|
|
mIdleTimer->stop();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void resetKernelIdleTimer() {
|
||
|
|
if (mIdleTimer && mConfig.kernelIdleTimerController) {
|
||
|
|
mIdleTimer->reset();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void resetIdleTimer() {
|
||
|
|
if (mIdleTimer) {
|
||
|
|
mIdleTimer->reset();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void dump(utils::Dumper&) const EXCLUDES(mLock);
|
||
|
|
|
||
|
|
std::chrono::milliseconds getIdleTimerTimeout();
|
||
|
|
|
||
|
|
private:
|
||
|
|
friend struct TestableRefreshRateSelector;
|
||
|
|
|
||
|
|
void constructAvailableRefreshRates() REQUIRES(mLock);
|
||
|
|
|
||
|
|
// See mActiveModeOpt for thread safety.
|
||
|
|
const FrameRateMode& getActiveModeLocked() const REQUIRES(mLock);
|
||
|
|
|
||
|
|
RankedFrameRates getRankedFrameRatesLocked(const std::vector<LayerRequirement>& layers,
|
||
|
|
GlobalSignals signals) const REQUIRES(mLock);
|
||
|
|
|
||
|
|
// Returns number of display frames and remainder when dividing the layer refresh period by
|
||
|
|
// display refresh period.
|
||
|
|
std::pair<nsecs_t, nsecs_t> 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);
|
||
|
|
|
||
|
|
#ifdef MTK_SF_MSYNC_3
|
||
|
|
const FrameRateMode& getSpecificRefreshRateByFpsLocked(int fps) const REQUIRES(mLock);
|
||
|
|
void getPkgName(const std::string& layerName, std::vector<std::string>& vecPkgName) const;
|
||
|
|
bool isPromoteLayer(const LayerRequirement& layer) const;
|
||
|
|
#endif
|
||
|
|
|
||
|
|
struct RefreshRateScoreComparator;
|
||
|
|
|
||
|
|
enum class RefreshRateOrder {
|
||
|
|
Ascending,
|
||
|
|
Descending,
|
||
|
|
|
||
|
|
ftl_last = Descending
|
||
|
|
};
|
||
|
|
|
||
|
|
// Only uses the primary range, not the app request range.
|
||
|
|
FrameRateRanking rankFrameRates(
|
||
|
|
std::optional<int> anchorGroupOpt, RefreshRateOrder refreshRateOrder,
|
||
|
|
std::optional<DisplayModeId> 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 calculateDistanceScoreFromMax(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<IdleTimerCallbacks::Callbacks> getIdleTimerCallbacks() const
|
||
|
|
REQUIRES(mIdleTimerCallbacksMutex) {
|
||
|
|
if (!mIdleTimerCallbacks) return {};
|
||
|
|
return mConfig.kernelIdleTimerController.has_value() ? mIdleTimerCallbacks->kernel
|
||
|
|
: 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
|
||
|
|
// 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);
|
||
|
|
|
||
|
|
// Set of supported display refresh rates for easy lookup
|
||
|
|
// when FrameRateOverride::AppOverrideNativeRefreshRates is in use.
|
||
|
|
ftl::SmallMap<Fps, ftl::Unit, 8, FpsApproxEqual> mAppOverrideNativeRefreshRates;
|
||
|
|
|
||
|
|
ftl::Optional<FrameRateMode> mActiveModeOpt GUARDED_BY(mLock);
|
||
|
|
|
||
|
|
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<FrameRateMode> mPrimaryFrameRates GUARDED_BY(mLock);
|
||
|
|
std::vector<FrameRateMode> mAppRequestFrameRates GUARDED_BY(mLock);
|
||
|
|
|
||
|
|
Policy mDisplayManagerPolicy GUARDED_BY(mLock);
|
||
|
|
std::optional<Policy> 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<Fps> mKnownFrameRates;
|
||
|
|
|
||
|
|
const Config mConfig;
|
||
|
|
Config::FrameRateOverride mFrameRateOverrideConfig;
|
||
|
|
|
||
|
|
struct GetRankedFrameRatesCache {
|
||
|
|
std::pair<std::vector<LayerRequirement>, GlobalSignals> arguments;
|
||
|
|
RankedFrameRates result;
|
||
|
|
};
|
||
|
|
mutable std::optional<GetRankedFrameRatesCache> mGetRankedFrameRatesCache GUARDED_BY(mLock);
|
||
|
|
|
||
|
|
// Declare mIdleTimer last to ensure its thread joins before the mutex/callbacks are destroyed.
|
||
|
|
std::mutex mIdleTimerCallbacksMutex;
|
||
|
|
std::optional<IdleTimerCallbacks> mIdleTimerCallbacks GUARDED_BY(mIdleTimerCallbacksMutex);
|
||
|
|
// Used to detect (lack of) frame activity.
|
||
|
|
ftl::Optional<scheduler::OneShotTimer> mIdleTimer;
|
||
|
|
};
|
||
|
|
|
||
|
|
} // namespace android::scheduler
|