Loading services/surfaceflinger/Scheduler/LayerHistoryV2.cpp +1 −1 Original line number Original line Diff line number Diff line Loading @@ -90,7 +90,7 @@ LayerHistoryV2::~LayerHistoryV2() = default; void LayerHistoryV2::registerLayer(Layer* layer, float /*lowRefreshRate*/, float highRefreshRate, void LayerHistoryV2::registerLayer(Layer* layer, float /*lowRefreshRate*/, float highRefreshRate, LayerVoteType type) { LayerVoteType type) { const nsecs_t highRefreshRatePeriod = static_cast<nsecs_t>(1e9f / highRefreshRate); const nsecs_t highRefreshRatePeriod = static_cast<nsecs_t>(1e9f / highRefreshRate); auto info = std::make_unique<LayerInfoV2>(highRefreshRatePeriod, type); auto info = std::make_unique<LayerInfoV2>(layer->getName(), highRefreshRatePeriod, type); std::lock_guard lock(mLock); std::lock_guard lock(mLock); mLayerInfos.emplace_back(layer, std::move(info)); mLayerInfos.emplace_back(layer, std::move(info)); } } Loading services/surfaceflinger/Scheduler/LayerInfoV2.cpp +19 −36 Original line number Original line Diff line number Diff line Loading @@ -27,8 +27,10 @@ namespace android::scheduler { namespace android::scheduler { LayerInfoV2::LayerInfoV2(nsecs_t highRefreshRatePeriod, LayerHistory::LayerVoteType defaultVote) LayerInfoV2::LayerInfoV2(const std::string& name, nsecs_t highRefreshRatePeriod, : mHighRefreshRatePeriod(highRefreshRatePeriod), LayerHistory::LayerVoteType defaultVote) : mName(name), mHighRefreshRatePeriod(highRefreshRatePeriod), mDefaultVote(defaultVote), mDefaultVote(defaultVote), mLayerVote({defaultVote, 0.0f}) {} mLayerVote({defaultVote, 0.0f}) {} Loading @@ -45,54 +47,31 @@ void LayerInfoV2::setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now) { } } } } bool LayerInfoV2::isFrameTimeValid(const FrameTimeData& frameTime) const { return frameTime.queueTime >= std::chrono::duration_cast<std::chrono::nanoseconds>( mFrameTimeValidSince.time_since_epoch()) .count(); } bool LayerInfoV2::isFrequent(nsecs_t now) const { bool LayerInfoV2::isFrequent(nsecs_t now) const { // Find the first valid frame time for (auto it = mFrameTimes.crbegin(); it != mFrameTimes.crend(); ++it) { auto it = mFrameTimes.begin(); if (now - it->queueTime >= MAX_FREQUENT_LAYER_PERIOD_NS.count()) { for (; it != mFrameTimes.end(); ++it) { ALOGV("%s infrequent (last frame is %.2fms ago", mName.c_str(), if (isFrameTimeValid(*it)) { (now - mFrameTimes.back().queueTime) / 1e6f); break; return false; } } } // If we know nothing about this layer we consider it as frequent as it might be the start const auto numFrames = std::distance(mFrameTimes.crbegin(), it + 1); // of an animation. if (numFrames >= FREQUENT_LAYER_WINDOW_SIZE) { if (std::distance(it, mFrameTimes.end()) < FREQUENT_LAYER_WINDOW_SIZE) { ALOGV("%s frequent (burst of %zu frames", mName.c_str(), numFrames); return true; return true; } } // Find the first active frame for (; it != mFrameTimes.end(); ++it) { if (it->queueTime >= getActiveLayerThreshold(now)) { break; } } } const auto numFrames = std::distance(it, mFrameTimes.end()); ALOGV("%s infrequent (not enough frames %zu)", mName.c_str(), mFrameTimes.size()); if (numFrames < FREQUENT_LAYER_WINDOW_SIZE) { return false; return false; } } // Layer is considered frequent if the average frame rate is higher than the threshold const auto totalTime = mFrameTimes.back().queueTime - it->queueTime; return (1e9f * (numFrames - 1)) / totalTime >= MIN_FPS_FOR_FREQUENT_LAYER; } bool LayerInfoV2::hasEnoughDataForHeuristic() const { bool LayerInfoV2::hasEnoughDataForHeuristic() const { // The layer had to publish at least HISTORY_SIZE or HISTORY_TIME of updates // The layer had to publish at least HISTORY_SIZE or HISTORY_TIME of updates if (mFrameTimes.size() < 2) { if (mFrameTimes.size() < 2) { return false; return false; } } if (!isFrameTimeValid(mFrameTimes.front())) { return false; } if (mFrameTimes.size() < HISTORY_SIZE && if (mFrameTimes.size() < HISTORY_SIZE && mFrameTimes.back().queueTime - mFrameTimes.front().queueTime < HISTORY_TIME.count()) { mFrameTimes.back().queueTime - mFrameTimes.front().queueTime < HISTORY_TIME.count()) { return false; return false; Loading Loading @@ -167,18 +146,22 @@ std::optional<float> LayerInfoV2::calculateRefreshRateIfPossible() { std::pair<LayerHistory::LayerVoteType, float> LayerInfoV2::getRefreshRate(nsecs_t now) { std::pair<LayerHistory::LayerVoteType, float> LayerInfoV2::getRefreshRate(nsecs_t now) { if (mLayerVote.type != LayerHistory::LayerVoteType::Heuristic) { if (mLayerVote.type != LayerHistory::LayerVoteType::Heuristic) { ALOGV("%s voted %d ", mName.c_str(), static_cast<int>(mLayerVote.type)); return {mLayerVote.type, mLayerVote.fps}; return {mLayerVote.type, mLayerVote.fps}; } } if (!isFrequent(now)) { if (!isFrequent(now)) { ALOGV("%s is infrequent", mName.c_str()); return {LayerHistory::LayerVoteType::Min, 0}; return {LayerHistory::LayerVoteType::Min, 0}; } } auto refreshRate = calculateRefreshRateIfPossible(); auto refreshRate = calculateRefreshRateIfPossible(); if (refreshRate.has_value()) { if (refreshRate.has_value()) { ALOGV("%s calculated refresh rate: %.2f", mName.c_str(), refreshRate.value()); return {LayerHistory::LayerVoteType::Heuristic, refreshRate.value()}; return {LayerHistory::LayerVoteType::Heuristic, refreshRate.value()}; } } ALOGV("%s Max (can't resolve refresh rate", mName.c_str()); return {LayerHistory::LayerVoteType::Max, 0}; return {LayerHistory::LayerVoteType::Max, 0}; } } Loading services/surfaceflinger/Scheduler/LayerInfoV2.h +5 −9 Original line number Original line Diff line number Diff line Loading @@ -54,7 +54,8 @@ class LayerInfoV2 { friend class LayerHistoryTestV2; friend class LayerHistoryTestV2; public: public: LayerInfoV2(nsecs_t highRefreshRatePeriod, LayerHistory::LayerVoteType defaultVote); LayerInfoV2(const std::string& name, nsecs_t highRefreshRatePeriod, LayerHistory::LayerVoteType defaultVote); LayerInfoV2(const LayerInfo&) = delete; LayerInfoV2(const LayerInfo&) = delete; LayerInfoV2& operator=(const LayerInfoV2&) = delete; LayerInfoV2& operator=(const LayerInfoV2&) = delete; Loading Loading @@ -83,11 +84,7 @@ public: nsecs_t getLastUpdatedTime() const { return mLastUpdatedTime; } nsecs_t getLastUpdatedTime() const { return mLastUpdatedTime; } void clearHistory() { void clearHistory() { // Mark mFrameTimeValidSince to now to ignore all previous frame times. mFrameTimes.clear(); // We are not deleting the old frame to keep track of whether we should treat the first // buffer as Max as we don't know anything about this layer or Min as this layer is // posting infrequent updates. mFrameTimeValidSince = std::chrono::steady_clock::now(); mLastReportedRefreshRate = 0.0f; mLastReportedRefreshRate = 0.0f; } } Loading @@ -101,7 +98,8 @@ private: bool isFrequent(nsecs_t now) const; bool isFrequent(nsecs_t now) const; bool hasEnoughDataForHeuristic() const; bool hasEnoughDataForHeuristic() const; std::optional<float> calculateRefreshRateIfPossible(); std::optional<float> calculateRefreshRateIfPossible(); bool isFrameTimeValid(const FrameTimeData&) const; const std::string mName; // Used for sanitizing the heuristic data // Used for sanitizing the heuristic data const nsecs_t mHighRefreshRatePeriod; const nsecs_t mHighRefreshRatePeriod; Loading @@ -118,8 +116,6 @@ private: } mLayerVote; } mLayerVote; std::deque<FrameTimeData> mFrameTimes; std::deque<FrameTimeData> mFrameTimes; std::chrono::time_point<std::chrono::steady_clock> mFrameTimeValidSince = std::chrono::steady_clock::now(); static constexpr size_t HISTORY_SIZE = 90; static constexpr size_t HISTORY_SIZE = 90; static constexpr std::chrono::nanoseconds HISTORY_TIME = 1s; static constexpr std::chrono::nanoseconds HISTORY_TIME = 1s; }; }; Loading services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +11 −6 Original line number Original line Diff line number Diff line Loading @@ -103,7 +103,7 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate( ATRACE_CALL(); ATRACE_CALL(); ALOGV("getRefreshRateForContent %zu layers", layers.size()); ALOGV("getRefreshRateForContent %zu layers", layers.size()); *touchConsidered = false; if (touchConsidered) *touchConsidered = false; std::lock_guard lock(mLock); std::lock_guard lock(mLock); int noVoteLayers = 0; int noVoteLayers = 0; Loading Loading @@ -131,7 +131,8 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate( // Consider the touch event if there are no Explicit* layers. Otherwise wait until after we've // 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. // selected a refresh rate to see if we should apply touch boost. if (touchActive && explicitDefaultVoteLayers == 0 && explicitExactOrMultipleVoteLayers == 0) { if (touchActive && explicitDefaultVoteLayers == 0 && explicitExactOrMultipleVoteLayers == 0) { *touchConsidered = true; ALOGV("TouchBoost - choose %s", getMaxRefreshRateByPolicyLocked().getName().c_str()); if (touchConsidered) *touchConsidered = true; return getMaxRefreshRateByPolicyLocked(); return getMaxRefreshRateByPolicyLocked(); } } Loading @@ -145,6 +146,7 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate( // Only if all layers want Min we should return Min // Only if all layers want Min we should return Min if (noVoteLayers + minVoteLayers == layers.size()) { if (noVoteLayers + minVoteLayers == layers.size()) { ALOGV("all layers Min - choose %s", getMinRefreshRateByPolicyLocked().getName().c_str()); return getMinRefreshRateByPolicyLocked(); return getMinRefreshRateByPolicyLocked(); } } Loading Loading @@ -243,9 +245,11 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate( return 1.0f / iter; return 1.0f / iter; }(); }(); ALOGV("%s (ExplicitExactOrMultiple, weight %.2f) %.2fHz gives %s score of %.2f", ALOGV("%s (%s, weight %.2f) %.2fHz gives %s score of %.2f", layer.name.c_str(), layer.name.c_str(), weight, 1e9f / layerPeriod, scores[i].first->name.c_str(), layer.vote == LayerVoteType::ExplicitExactOrMultiple layerScore); ? "ExplicitExactOrMultiple" : "Heuristic", weight, 1e9f / layerPeriod, scores[i].first->name.c_str(), layerScore); scores[i].second += weight * layerScore; scores[i].second += weight * layerScore; continue; continue; } } Loading @@ -266,7 +270,8 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate( const RefreshRate& touchRefreshRate = getMaxRefreshRateByPolicyLocked(); const RefreshRate& touchRefreshRate = getMaxRefreshRateByPolicyLocked(); if (touchActive && explicitDefaultVoteLayers == 0 && if (touchActive && explicitDefaultVoteLayers == 0 && bestRefreshRate->fps < touchRefreshRate.fps) { bestRefreshRate->fps < touchRefreshRate.fps) { *touchConsidered = true; if (touchConsidered) *touchConsidered = true; ALOGV("TouchBoost - choose %s", touchRefreshRate.getName().c_str()); return touchRefreshRate; return touchRefreshRate; } } Loading services/surfaceflinger/Scheduler/Scheduler.cpp +14 −18 Original line number Original line Diff line number Diff line Loading @@ -526,7 +526,9 @@ void Scheduler::idleTimerCallback(TimerState state) { void Scheduler::touchTimerCallback(TimerState state) { void Scheduler::touchTimerCallback(TimerState state) { const TouchState touch = state == TimerState::Reset ? TouchState::Active : TouchState::Inactive; const TouchState touch = state == TimerState::Reset ? TouchState::Active : TouchState::Inactive; handleTimerStateChanged(&mFeatures.touch, touch, true /* eventOnContentDetection */); if (handleTimerStateChanged(&mFeatures.touch, touch, true /* eventOnContentDetection */)) { mLayerHistory->clear(); } ATRACE_INT("TouchState", static_cast<int>(touch)); ATRACE_INT("TouchState", static_cast<int>(touch)); } } Loading @@ -549,18 +551,19 @@ void Scheduler::dump(std::string& result) const { } } template <class T> template <class T> void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventOnContentDetection) { bool Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventOnContentDetection) { ConfigEvent event = ConfigEvent::None; ConfigEvent event = ConfigEvent::None; HwcConfigIndexType newConfigId; HwcConfigIndexType newConfigId; bool touchConsidered = false; { { std::lock_guard<std::mutex> lock(mFeatureStateLock); std::lock_guard<std::mutex> lock(mFeatureStateLock); if (*currentState == newState) { if (*currentState == newState) { return; return touchConsidered; } } *currentState = newState; *currentState = newState; newConfigId = calculateRefreshRateConfigIndexType(); newConfigId = calculateRefreshRateConfigIndexType(&touchConsidered); if (mFeatures.configId == newConfigId) { if (mFeatures.configId == newConfigId) { return; return touchConsidered; } } mFeatures.configId = newConfigId; mFeatures.configId = newConfigId; if (eventOnContentDetection && !mFeatures.contentRequirements.empty()) { if (eventOnContentDetection && !mFeatures.contentRequirements.empty()) { Loading @@ -569,10 +572,12 @@ void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventO } } const RefreshRate& newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId); const RefreshRate& newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId); mSchedulerCallback.changeRefreshRate(newRefreshRate, event); mSchedulerCallback.changeRefreshRate(newRefreshRate, event); return touchConsidered; } } HwcConfigIndexType Scheduler::calculateRefreshRateConfigIndexType() { HwcConfigIndexType Scheduler::calculateRefreshRateConfigIndexType(bool* touchConsidered) { ATRACE_CALL(); ATRACE_CALL(); if (touchConsidered) *touchConsidered = false; // If Display Power is not in normal operation we want to be in performance mode. When coming // If Display Power is not in normal operation we want to be in performance mode. When coming // back to normal mode, a grace period is given with DisplayPowerTimer. // back to normal mode, a grace period is given with DisplayPowerTimer. Loading Loading @@ -607,18 +612,9 @@ HwcConfigIndexType Scheduler::calculateRefreshRateConfigIndexType() { .getConfigId(); .getConfigId(); } } bool touchConsidered; return mRefreshRateConfigs const auto& ret = mRefreshRateConfigs .getBestRefreshRate(mFeatures.contentRequirements, touchActive, idle, touchConsidered) .getBestRefreshRate(mFeatures.contentRequirements, touchActive, idle, &touchConsidered) .getConfigId(); .getConfigId(); if (touchConsidered) { // Clear layer history if refresh rate was selected based on touch to allow // the hueristic to pick up with the new rate. mLayerHistory->clear(); } return ret; } } std::optional<HwcConfigIndexType> Scheduler::getPreferredConfigId() { std::optional<HwcConfigIndexType> Scheduler::getPreferredConfigId() { Loading Loading
services/surfaceflinger/Scheduler/LayerHistoryV2.cpp +1 −1 Original line number Original line Diff line number Diff line Loading @@ -90,7 +90,7 @@ LayerHistoryV2::~LayerHistoryV2() = default; void LayerHistoryV2::registerLayer(Layer* layer, float /*lowRefreshRate*/, float highRefreshRate, void LayerHistoryV2::registerLayer(Layer* layer, float /*lowRefreshRate*/, float highRefreshRate, LayerVoteType type) { LayerVoteType type) { const nsecs_t highRefreshRatePeriod = static_cast<nsecs_t>(1e9f / highRefreshRate); const nsecs_t highRefreshRatePeriod = static_cast<nsecs_t>(1e9f / highRefreshRate); auto info = std::make_unique<LayerInfoV2>(highRefreshRatePeriod, type); auto info = std::make_unique<LayerInfoV2>(layer->getName(), highRefreshRatePeriod, type); std::lock_guard lock(mLock); std::lock_guard lock(mLock); mLayerInfos.emplace_back(layer, std::move(info)); mLayerInfos.emplace_back(layer, std::move(info)); } } Loading
services/surfaceflinger/Scheduler/LayerInfoV2.cpp +19 −36 Original line number Original line Diff line number Diff line Loading @@ -27,8 +27,10 @@ namespace android::scheduler { namespace android::scheduler { LayerInfoV2::LayerInfoV2(nsecs_t highRefreshRatePeriod, LayerHistory::LayerVoteType defaultVote) LayerInfoV2::LayerInfoV2(const std::string& name, nsecs_t highRefreshRatePeriod, : mHighRefreshRatePeriod(highRefreshRatePeriod), LayerHistory::LayerVoteType defaultVote) : mName(name), mHighRefreshRatePeriod(highRefreshRatePeriod), mDefaultVote(defaultVote), mDefaultVote(defaultVote), mLayerVote({defaultVote, 0.0f}) {} mLayerVote({defaultVote, 0.0f}) {} Loading @@ -45,54 +47,31 @@ void LayerInfoV2::setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now) { } } } } bool LayerInfoV2::isFrameTimeValid(const FrameTimeData& frameTime) const { return frameTime.queueTime >= std::chrono::duration_cast<std::chrono::nanoseconds>( mFrameTimeValidSince.time_since_epoch()) .count(); } bool LayerInfoV2::isFrequent(nsecs_t now) const { bool LayerInfoV2::isFrequent(nsecs_t now) const { // Find the first valid frame time for (auto it = mFrameTimes.crbegin(); it != mFrameTimes.crend(); ++it) { auto it = mFrameTimes.begin(); if (now - it->queueTime >= MAX_FREQUENT_LAYER_PERIOD_NS.count()) { for (; it != mFrameTimes.end(); ++it) { ALOGV("%s infrequent (last frame is %.2fms ago", mName.c_str(), if (isFrameTimeValid(*it)) { (now - mFrameTimes.back().queueTime) / 1e6f); break; return false; } } } // If we know nothing about this layer we consider it as frequent as it might be the start const auto numFrames = std::distance(mFrameTimes.crbegin(), it + 1); // of an animation. if (numFrames >= FREQUENT_LAYER_WINDOW_SIZE) { if (std::distance(it, mFrameTimes.end()) < FREQUENT_LAYER_WINDOW_SIZE) { ALOGV("%s frequent (burst of %zu frames", mName.c_str(), numFrames); return true; return true; } } // Find the first active frame for (; it != mFrameTimes.end(); ++it) { if (it->queueTime >= getActiveLayerThreshold(now)) { break; } } } const auto numFrames = std::distance(it, mFrameTimes.end()); ALOGV("%s infrequent (not enough frames %zu)", mName.c_str(), mFrameTimes.size()); if (numFrames < FREQUENT_LAYER_WINDOW_SIZE) { return false; return false; } } // Layer is considered frequent if the average frame rate is higher than the threshold const auto totalTime = mFrameTimes.back().queueTime - it->queueTime; return (1e9f * (numFrames - 1)) / totalTime >= MIN_FPS_FOR_FREQUENT_LAYER; } bool LayerInfoV2::hasEnoughDataForHeuristic() const { bool LayerInfoV2::hasEnoughDataForHeuristic() const { // The layer had to publish at least HISTORY_SIZE or HISTORY_TIME of updates // The layer had to publish at least HISTORY_SIZE or HISTORY_TIME of updates if (mFrameTimes.size() < 2) { if (mFrameTimes.size() < 2) { return false; return false; } } if (!isFrameTimeValid(mFrameTimes.front())) { return false; } if (mFrameTimes.size() < HISTORY_SIZE && if (mFrameTimes.size() < HISTORY_SIZE && mFrameTimes.back().queueTime - mFrameTimes.front().queueTime < HISTORY_TIME.count()) { mFrameTimes.back().queueTime - mFrameTimes.front().queueTime < HISTORY_TIME.count()) { return false; return false; Loading Loading @@ -167,18 +146,22 @@ std::optional<float> LayerInfoV2::calculateRefreshRateIfPossible() { std::pair<LayerHistory::LayerVoteType, float> LayerInfoV2::getRefreshRate(nsecs_t now) { std::pair<LayerHistory::LayerVoteType, float> LayerInfoV2::getRefreshRate(nsecs_t now) { if (mLayerVote.type != LayerHistory::LayerVoteType::Heuristic) { if (mLayerVote.type != LayerHistory::LayerVoteType::Heuristic) { ALOGV("%s voted %d ", mName.c_str(), static_cast<int>(mLayerVote.type)); return {mLayerVote.type, mLayerVote.fps}; return {mLayerVote.type, mLayerVote.fps}; } } if (!isFrequent(now)) { if (!isFrequent(now)) { ALOGV("%s is infrequent", mName.c_str()); return {LayerHistory::LayerVoteType::Min, 0}; return {LayerHistory::LayerVoteType::Min, 0}; } } auto refreshRate = calculateRefreshRateIfPossible(); auto refreshRate = calculateRefreshRateIfPossible(); if (refreshRate.has_value()) { if (refreshRate.has_value()) { ALOGV("%s calculated refresh rate: %.2f", mName.c_str(), refreshRate.value()); return {LayerHistory::LayerVoteType::Heuristic, refreshRate.value()}; return {LayerHistory::LayerVoteType::Heuristic, refreshRate.value()}; } } ALOGV("%s Max (can't resolve refresh rate", mName.c_str()); return {LayerHistory::LayerVoteType::Max, 0}; return {LayerHistory::LayerVoteType::Max, 0}; } } Loading
services/surfaceflinger/Scheduler/LayerInfoV2.h +5 −9 Original line number Original line Diff line number Diff line Loading @@ -54,7 +54,8 @@ class LayerInfoV2 { friend class LayerHistoryTestV2; friend class LayerHistoryTestV2; public: public: LayerInfoV2(nsecs_t highRefreshRatePeriod, LayerHistory::LayerVoteType defaultVote); LayerInfoV2(const std::string& name, nsecs_t highRefreshRatePeriod, LayerHistory::LayerVoteType defaultVote); LayerInfoV2(const LayerInfo&) = delete; LayerInfoV2(const LayerInfo&) = delete; LayerInfoV2& operator=(const LayerInfoV2&) = delete; LayerInfoV2& operator=(const LayerInfoV2&) = delete; Loading Loading @@ -83,11 +84,7 @@ public: nsecs_t getLastUpdatedTime() const { return mLastUpdatedTime; } nsecs_t getLastUpdatedTime() const { return mLastUpdatedTime; } void clearHistory() { void clearHistory() { // Mark mFrameTimeValidSince to now to ignore all previous frame times. mFrameTimes.clear(); // We are not deleting the old frame to keep track of whether we should treat the first // buffer as Max as we don't know anything about this layer or Min as this layer is // posting infrequent updates. mFrameTimeValidSince = std::chrono::steady_clock::now(); mLastReportedRefreshRate = 0.0f; mLastReportedRefreshRate = 0.0f; } } Loading @@ -101,7 +98,8 @@ private: bool isFrequent(nsecs_t now) const; bool isFrequent(nsecs_t now) const; bool hasEnoughDataForHeuristic() const; bool hasEnoughDataForHeuristic() const; std::optional<float> calculateRefreshRateIfPossible(); std::optional<float> calculateRefreshRateIfPossible(); bool isFrameTimeValid(const FrameTimeData&) const; const std::string mName; // Used for sanitizing the heuristic data // Used for sanitizing the heuristic data const nsecs_t mHighRefreshRatePeriod; const nsecs_t mHighRefreshRatePeriod; Loading @@ -118,8 +116,6 @@ private: } mLayerVote; } mLayerVote; std::deque<FrameTimeData> mFrameTimes; std::deque<FrameTimeData> mFrameTimes; std::chrono::time_point<std::chrono::steady_clock> mFrameTimeValidSince = std::chrono::steady_clock::now(); static constexpr size_t HISTORY_SIZE = 90; static constexpr size_t HISTORY_SIZE = 90; static constexpr std::chrono::nanoseconds HISTORY_TIME = 1s; static constexpr std::chrono::nanoseconds HISTORY_TIME = 1s; }; }; Loading
services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +11 −6 Original line number Original line Diff line number Diff line Loading @@ -103,7 +103,7 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate( ATRACE_CALL(); ATRACE_CALL(); ALOGV("getRefreshRateForContent %zu layers", layers.size()); ALOGV("getRefreshRateForContent %zu layers", layers.size()); *touchConsidered = false; if (touchConsidered) *touchConsidered = false; std::lock_guard lock(mLock); std::lock_guard lock(mLock); int noVoteLayers = 0; int noVoteLayers = 0; Loading Loading @@ -131,7 +131,8 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate( // Consider the touch event if there are no Explicit* layers. Otherwise wait until after we've // 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. // selected a refresh rate to see if we should apply touch boost. if (touchActive && explicitDefaultVoteLayers == 0 && explicitExactOrMultipleVoteLayers == 0) { if (touchActive && explicitDefaultVoteLayers == 0 && explicitExactOrMultipleVoteLayers == 0) { *touchConsidered = true; ALOGV("TouchBoost - choose %s", getMaxRefreshRateByPolicyLocked().getName().c_str()); if (touchConsidered) *touchConsidered = true; return getMaxRefreshRateByPolicyLocked(); return getMaxRefreshRateByPolicyLocked(); } } Loading @@ -145,6 +146,7 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate( // Only if all layers want Min we should return Min // Only if all layers want Min we should return Min if (noVoteLayers + minVoteLayers == layers.size()) { if (noVoteLayers + minVoteLayers == layers.size()) { ALOGV("all layers Min - choose %s", getMinRefreshRateByPolicyLocked().getName().c_str()); return getMinRefreshRateByPolicyLocked(); return getMinRefreshRateByPolicyLocked(); } } Loading Loading @@ -243,9 +245,11 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate( return 1.0f / iter; return 1.0f / iter; }(); }(); ALOGV("%s (ExplicitExactOrMultiple, weight %.2f) %.2fHz gives %s score of %.2f", ALOGV("%s (%s, weight %.2f) %.2fHz gives %s score of %.2f", layer.name.c_str(), layer.name.c_str(), weight, 1e9f / layerPeriod, scores[i].first->name.c_str(), layer.vote == LayerVoteType::ExplicitExactOrMultiple layerScore); ? "ExplicitExactOrMultiple" : "Heuristic", weight, 1e9f / layerPeriod, scores[i].first->name.c_str(), layerScore); scores[i].second += weight * layerScore; scores[i].second += weight * layerScore; continue; continue; } } Loading @@ -266,7 +270,8 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate( const RefreshRate& touchRefreshRate = getMaxRefreshRateByPolicyLocked(); const RefreshRate& touchRefreshRate = getMaxRefreshRateByPolicyLocked(); if (touchActive && explicitDefaultVoteLayers == 0 && if (touchActive && explicitDefaultVoteLayers == 0 && bestRefreshRate->fps < touchRefreshRate.fps) { bestRefreshRate->fps < touchRefreshRate.fps) { *touchConsidered = true; if (touchConsidered) *touchConsidered = true; ALOGV("TouchBoost - choose %s", touchRefreshRate.getName().c_str()); return touchRefreshRate; return touchRefreshRate; } } Loading
services/surfaceflinger/Scheduler/Scheduler.cpp +14 −18 Original line number Original line Diff line number Diff line Loading @@ -526,7 +526,9 @@ void Scheduler::idleTimerCallback(TimerState state) { void Scheduler::touchTimerCallback(TimerState state) { void Scheduler::touchTimerCallback(TimerState state) { const TouchState touch = state == TimerState::Reset ? TouchState::Active : TouchState::Inactive; const TouchState touch = state == TimerState::Reset ? TouchState::Active : TouchState::Inactive; handleTimerStateChanged(&mFeatures.touch, touch, true /* eventOnContentDetection */); if (handleTimerStateChanged(&mFeatures.touch, touch, true /* eventOnContentDetection */)) { mLayerHistory->clear(); } ATRACE_INT("TouchState", static_cast<int>(touch)); ATRACE_INT("TouchState", static_cast<int>(touch)); } } Loading @@ -549,18 +551,19 @@ void Scheduler::dump(std::string& result) const { } } template <class T> template <class T> void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventOnContentDetection) { bool Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventOnContentDetection) { ConfigEvent event = ConfigEvent::None; ConfigEvent event = ConfigEvent::None; HwcConfigIndexType newConfigId; HwcConfigIndexType newConfigId; bool touchConsidered = false; { { std::lock_guard<std::mutex> lock(mFeatureStateLock); std::lock_guard<std::mutex> lock(mFeatureStateLock); if (*currentState == newState) { if (*currentState == newState) { return; return touchConsidered; } } *currentState = newState; *currentState = newState; newConfigId = calculateRefreshRateConfigIndexType(); newConfigId = calculateRefreshRateConfigIndexType(&touchConsidered); if (mFeatures.configId == newConfigId) { if (mFeatures.configId == newConfigId) { return; return touchConsidered; } } mFeatures.configId = newConfigId; mFeatures.configId = newConfigId; if (eventOnContentDetection && !mFeatures.contentRequirements.empty()) { if (eventOnContentDetection && !mFeatures.contentRequirements.empty()) { Loading @@ -569,10 +572,12 @@ void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventO } } const RefreshRate& newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId); const RefreshRate& newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId); mSchedulerCallback.changeRefreshRate(newRefreshRate, event); mSchedulerCallback.changeRefreshRate(newRefreshRate, event); return touchConsidered; } } HwcConfigIndexType Scheduler::calculateRefreshRateConfigIndexType() { HwcConfigIndexType Scheduler::calculateRefreshRateConfigIndexType(bool* touchConsidered) { ATRACE_CALL(); ATRACE_CALL(); if (touchConsidered) *touchConsidered = false; // If Display Power is not in normal operation we want to be in performance mode. When coming // If Display Power is not in normal operation we want to be in performance mode. When coming // back to normal mode, a grace period is given with DisplayPowerTimer. // back to normal mode, a grace period is given with DisplayPowerTimer. Loading Loading @@ -607,18 +612,9 @@ HwcConfigIndexType Scheduler::calculateRefreshRateConfigIndexType() { .getConfigId(); .getConfigId(); } } bool touchConsidered; return mRefreshRateConfigs const auto& ret = mRefreshRateConfigs .getBestRefreshRate(mFeatures.contentRequirements, touchActive, idle, touchConsidered) .getBestRefreshRate(mFeatures.contentRequirements, touchActive, idle, &touchConsidered) .getConfigId(); .getConfigId(); if (touchConsidered) { // Clear layer history if refresh rate was selected based on touch to allow // the hueristic to pick up with the new rate. mLayerHistory->clear(); } return ret; } } std::optional<HwcConfigIndexType> Scheduler::getPreferredConfigId() { std::optional<HwcConfigIndexType> Scheduler::getPreferredConfigId() { Loading