Loading libs/ui/include/ui/DisplayId.h +6 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #pragma once #include <cstdint> #include <ostream> #include <string> #include <ftl/optional.h> Loading Loading @@ -67,6 +68,11 @@ inline std::string to_string(DisplayId displayId) { return std::to_string(displayId.value); } // For tests. inline std::ostream& operator<<(std::ostream& stream, DisplayId displayId) { return stream << "DisplayId{" << displayId.value << '}'; } // DisplayId of a physical display, such as the internal display or externally connected display. struct PhysicalDisplayId : DisplayId { static constexpr ftl::Optional<PhysicalDisplayId> tryCast(DisplayId id) { Loading services/surfaceflinger/Display/DisplayModeRequest.h 0 → 100644 +36 −0 Original line number Diff line number Diff line /* * Copyright 2022 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 <ftl/non_null.h> #include "DisplayHardware/DisplayMode.h" namespace android::display { struct DisplayModeRequest { ftl::NonNull<DisplayModePtr> modePtr; // Whether to emit DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE. bool emitEvent = false; }; inline bool operator==(const DisplayModeRequest& lhs, const DisplayModeRequest& rhs) { return lhs.modePtr == rhs.modePtr && lhs.emitEvent == rhs.emitEvent; } } // namespace android::display services/surfaceflinger/DisplayDevice.h +13 −1 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ #include <utils/RefBase.h> #include <utils/Timers.h> #include "Display/DisplayModeRequest.h" #include "DisplayHardware/DisplayMode.h" #include "DisplayHardware/Hal.h" #include "DisplayHardware/PowerAdvisor.h" Loading Loading @@ -190,9 +191,20 @@ public: /* ------------------------------------------------------------------------ * Display mode management. */ // TODO(b/241285876): Replace ActiveModeInfo and DisplayModeEvent with DisplayModeRequest. struct ActiveModeInfo { using Event = scheduler::DisplayModeEvent; ActiveModeInfo() = default; ActiveModeInfo(DisplayModePtr mode, Event event) : mode(std::move(mode)), event(event) {} explicit ActiveModeInfo(display::DisplayModeRequest&& request) : ActiveModeInfo(std::move(request.modePtr).take(), request.emitEvent ? Event::Changed : Event::None) {} DisplayModePtr mode; scheduler::DisplayModeEvent event = scheduler::DisplayModeEvent::None; Event event = Event::None; bool operator!=(const ActiveModeInfo& other) const { return mode != other.mode || event != other.event; Loading services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +35 −45 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include <chrono> #include <cmath> #include <deque> #include <android-base/properties.h> #include <android-base/stringprintf.h> Loading Loading @@ -143,8 +144,7 @@ struct RefreshRateConfigs::RefreshRateScoreComparator { ATRACE_INT(name.c_str(), static_cast<int>(std::round(overallScore * 100))); constexpr float kEpsilon = 0.0001f; if (std::abs(overallScore - rhs.overallScore) > kEpsilon) { if (!ScoredRefreshRate::scoresEqual(overallScore, rhs.overallScore)) { return overallScore > rhs.overallScore; } Loading Loading @@ -288,8 +288,7 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye } auto RefreshRateConfigs::getRankedRefreshRates(const std::vector<LayerRequirement>& layers, GlobalSignals signals) const -> std::pair<std::vector<RefreshRateRanking>, GlobalSignals> { GlobalSignals signals) const -> RankedRefreshRates { std::lock_guard lock(mLock); if (mGetRankedRefreshRatesCache && Loading @@ -304,7 +303,7 @@ auto RefreshRateConfigs::getRankedRefreshRates(const std::vector<LayerRequiremen auto RefreshRateConfigs::getRankedRefreshRatesLocked(const std::vector<LayerRequirement>& layers, GlobalSignals signals) const -> std::pair<std::vector<RefreshRateRanking>, GlobalSignals> { -> RankedRefreshRates { using namespace fps_approx_ops; ATRACE_CALL(); ALOGV("%s: %zu layers", __func__, layers.size()); Loading @@ -314,8 +313,7 @@ auto RefreshRateConfigs::getRankedRefreshRatesLocked(const std::vector<LayerRequ // Keep the display at max refresh rate for the duration of powering on the display. if (signals.powerOnImminent) { ALOGV("Power On Imminent"); return {getRefreshRatesByPolicyLocked(activeMode.getGroup(), RefreshRateOrder::Descending, /*preferredDisplayModeOpt*/ std::nullopt), return {rankRefreshRates(activeMode.getGroup(), RefreshRateOrder::Descending), GlobalSignals{.powerOnImminent = true}}; } Loading Loading @@ -375,8 +373,7 @@ auto RefreshRateConfigs::getRankedRefreshRatesLocked(const std::vector<LayerRequ // selected a refresh rate to see if we should apply touch boost. if (signals.touch && !hasExplicitVoteLayers) { ALOGV("Touch Boost"); return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending, /*preferredDisplayModeOpt*/ std::nullopt), return {rankRefreshRates(anchorGroup, RefreshRateOrder::Descending), GlobalSignals{.touch = true}}; } Loading @@ -388,24 +385,19 @@ auto RefreshRateConfigs::getRankedRefreshRatesLocked(const std::vector<LayerRequ if (!signals.touch && signals.idle && !(primaryRangeIsSingleRate && hasExplicitVoteLayers)) { ALOGV("Idle"); return {getRefreshRatesByPolicyLocked(activeMode.getGroup(), RefreshRateOrder::Ascending, /*preferredDisplayModeOpt*/ std::nullopt), return {rankRefreshRates(activeMode.getGroup(), RefreshRateOrder::Ascending), GlobalSignals{.idle = true}}; } if (layers.empty() || noVoteLayers == layers.size()) { ALOGV("No layers with votes"); return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending, /*preferredDisplayModeOpt*/ std::nullopt), kNoSignals}; return {rankRefreshRates(anchorGroup, RefreshRateOrder::Descending), kNoSignals}; } // Only if all layers want Min we should return Min if (noVoteLayers + minVoteLayers == layers.size()) { ALOGV("All layers Min"); return {getRefreshRatesByPolicyLocked(activeMode.getGroup(), RefreshRateOrder::Ascending, /*preferredDisplayModeOpt*/ std::nullopt), kNoSignals}; return {rankRefreshRates(activeMode.getGroup(), RefreshRateOrder::Ascending), kNoSignals}; } // Find the best refresh rate based on score Loading Loading @@ -557,12 +549,13 @@ auto RefreshRateConfigs::getRankedRefreshRatesLocked(const std::vector<LayerRequ maxVoteLayers > 0 ? RefreshRateOrder::Descending : RefreshRateOrder::Ascending; std::sort(scores.begin(), scores.end(), RefreshRateScoreComparator{.refreshRateOrder = refreshRateOrder}); std::vector<RefreshRateRanking> rankedRefreshRates; rankedRefreshRates.reserve(scores.size()); std::transform(scores.begin(), scores.end(), back_inserter(rankedRefreshRates), RefreshRateRanking ranking; ranking.reserve(scores.size()); std::transform(scores.begin(), scores.end(), back_inserter(ranking), [](const RefreshRateScore& score) { return RefreshRateRanking{score.modeIt->second, score.overallScore}; return ScoredRefreshRate{score.modeIt->second, score.overallScore}; }); const bool noLayerScore = std::all_of(scores.begin(), scores.end(), [](RefreshRateScore score) { Loading @@ -574,11 +567,9 @@ auto RefreshRateConfigs::getRankedRefreshRatesLocked(const std::vector<LayerRequ // range instead of picking a random score from the app range. if (noLayerScore) { ALOGV("Layers not scored"); return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending, /*preferredDisplayModeOpt*/ std::nullopt), kNoSignals}; return {rankRefreshRates(anchorGroup, RefreshRateOrder::Descending), kNoSignals}; } else { return {rankedRefreshRates, kNoSignals}; return {ranking, kNoSignals}; } } Loading @@ -596,14 +587,12 @@ auto RefreshRateConfigs::getRankedRefreshRatesLocked(const std::vector<LayerRequ } }(); const auto& touchRefreshRates = getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending, /*preferredDisplayModeOpt*/ std::nullopt); const auto touchRefreshRates = rankRefreshRates(anchorGroup, RefreshRateOrder::Descending); using fps_approx_ops::operator<; if (signals.touch && explicitDefaultVoteLayers == 0 && touchBoostForExplicitExact && scores.front().modeIt->second->getFps() < touchRefreshRates.front().displayModePtr->getFps()) { scores.front().modeIt->second->getFps() < touchRefreshRates.front().modePtr->getFps()) { ALOGV("Touch Boost"); return {touchRefreshRates, GlobalSignals{.touch = true}}; } Loading @@ -612,12 +601,11 @@ auto RefreshRateConfigs::getRankedRefreshRatesLocked(const std::vector<LayerRequ // current config if (noLayerScore && refreshRateOrder == RefreshRateOrder::Ascending) { const auto preferredDisplayMode = activeMode.getId(); return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Ascending, preferredDisplayMode), return {rankRefreshRates(anchorGroup, RefreshRateOrder::Ascending, preferredDisplayMode), kNoSignals}; } return {rankedRefreshRates, kNoSignals}; return {ranking, kNoSignals}; } std::unordered_map<uid_t, std::vector<const RefreshRateConfigs::LayerRequirement*>> Loading Loading @@ -783,11 +771,12 @@ const DisplayModePtr& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked(int an return mPrimaryRefreshRates.back()->second; } std::vector<RefreshRateRanking> RefreshRateConfigs::getRefreshRatesByPolicyLocked( auto RefreshRateConfigs::rankRefreshRates( std::optional<int> anchorGroupOpt, RefreshRateOrder refreshRateOrder, std::optional<DisplayModeId> preferredDisplayModeOpt) const { std::deque<RefreshRateRanking> rankings; const auto makeRanking = [&](const DisplayModeIterator it) REQUIRES(mLock) { std::optional<DisplayModeId> preferredDisplayModeOpt) const -> RefreshRateRanking { std::deque<ScoredRefreshRate> ranking; const auto rankRefreshRate = [&](DisplayModeIterator it) REQUIRES(mLock) { const auto& mode = it->second; if (anchorGroupOpt && mode->getGroup() != anchorGroupOpt) { return; Loading @@ -800,31 +789,32 @@ std::vector<RefreshRateRanking> RefreshRateConfigs::getRefreshRatesByPolicyLocke } if (preferredDisplayModeOpt) { if (*preferredDisplayModeOpt == mode->getId()) { rankings.push_front(RefreshRateRanking{mode, /*score*/ 1.0f}); constexpr float kScore = std::numeric_limits<float>::max(); ranking.push_front(ScoredRefreshRate{mode, kScore}); return; } constexpr float kNonPreferredModePenalty = 0.95f; score *= kNonPreferredModePenalty; } rankings.push_back(RefreshRateRanking{mode, score}); ranking.push_back(ScoredRefreshRate{mode, score}); }; if (refreshRateOrder == RefreshRateOrder::Ascending) { std::for_each(mPrimaryRefreshRates.begin(), mPrimaryRefreshRates.end(), makeRanking); std::for_each(mPrimaryRefreshRates.begin(), mPrimaryRefreshRates.end(), rankRefreshRate); } else { std::for_each(mPrimaryRefreshRates.rbegin(), mPrimaryRefreshRates.rend(), makeRanking); std::for_each(mPrimaryRefreshRates.rbegin(), mPrimaryRefreshRates.rend(), rankRefreshRate); } if (!rankings.empty() || !anchorGroupOpt) { return {rankings.begin(), rankings.end()}; if (!ranking.empty() || !anchorGroupOpt) { return {ranking.begin(), ranking.end()}; } ALOGW("Can't find %s refresh rate by policy with the same mode group" " as the mode group %d", refreshRateOrder == RefreshRateOrder::Ascending ? "min" : "max", anchorGroupOpt.value()); return getRefreshRatesByPolicyLocked(/*anchorGroupOpt*/ std::nullopt, refreshRateOrder, preferredDisplayModeOpt); constexpr std::optional<int> kNoAnchorGroup = std::nullopt; return rankRefreshRates(kNoAnchorGroup, refreshRateOrder, preferredDisplayModeOpt); } DisplayModePtr RefreshRateConfigs::getActiveModePtr() const { Loading services/surfaceflinger/Scheduler/RefreshRateConfigs.h +45 −20 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include <utility> #include <variant> #include <ftl/concat.h> #include <gui/DisplayEventReceiver.h> #include <scheduler/Fps.h> Loading @@ -46,15 +47,6 @@ inline DisplayModeEvent operator|(DisplayModeEvent lhs, DisplayModeEvent rhs) { return static_cast<DisplayModeEvent>(static_cast<T>(lhs) | static_cast<T>(rhs)); } struct RefreshRateRanking { DisplayModePtr displayModePtr; float score = 0.0f; bool operator==(const RefreshRateRanking& ranking) const { return displayModePtr == ranking.displayModePtr && score == ranking.score; } }; using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride; /** Loading Loading @@ -208,12 +200,46 @@ public: return touch == other.touch && idle == other.idle && powerOnImminent == other.powerOnImminent; } auto toString() const { return ftl::Concat("{touch=", touch, ", idle=", idle, ", powerOnImminent=", powerOnImminent, '}'); } }; struct ScoredRefreshRate { DisplayModePtr modePtr; float score = 0.0f; bool operator==(const ScoredRefreshRate& other) const { return modePtr == other.modePtr && score == other.score; } static bool scoresEqual(float lhs, float rhs) { constexpr float kEpsilon = 0.0001f; return std::abs(lhs - rhs) <= kEpsilon; } struct DescendingScore { bool operator()(const ScoredRefreshRate& lhs, const ScoredRefreshRate& rhs) const { return lhs.score > rhs.score && !scoresEqual(lhs.score, rhs.score); } }; }; using RefreshRateRanking = std::vector<ScoredRefreshRate>; struct RankedRefreshRates { RefreshRateRanking ranking; // Ordered by descending score. GlobalSignals consideredSignals; bool operator==(const RankedRefreshRates& other) const { return ranking == other.ranking && consideredSignals == other.consideredSignals; } }; // Returns the list in the descending order of refresh rates desired // based on their overall score, and the GlobalSignals that were considered. std::pair<std::vector<RefreshRateRanking>, GlobalSignals> getRankedRefreshRates( const std::vector<LayerRequirement>&, GlobalSignals) const EXCLUDES(mLock); RankedRefreshRates getRankedRefreshRates(const std::vector<LayerRequirement>&, GlobalSignals) const EXCLUDES(mLock); FpsRange getSupportedRefreshRateRange() const EXCLUDES(mLock) { std::lock_guard lock(mLock); Loading Loading @@ -354,8 +380,8 @@ private: // See mActiveModeIt for thread safety. DisplayModeIterator getActiveModeItLocked() const REQUIRES(mLock); std::pair<std::vector<RefreshRateRanking>, GlobalSignals> getRankedRefreshRatesLocked( const std::vector<LayerRequirement>&, GlobalSignals) const REQUIRES(mLock); RankedRefreshRates getRankedRefreshRatesLocked(const std::vector<LayerRequirement>&, GlobalSignals) const REQUIRES(mLock); // Returns number of display frames and remainder when dividing the layer refresh period by // display refresh period. Loading @@ -373,11 +399,10 @@ private: enum class RefreshRateOrder { Ascending, Descending }; // Returns the rankings in RefreshRateOrder. May change at runtime. // Only uses the primary range, not the app request range. std::vector<RefreshRateRanking> getRefreshRatesByPolicyLocked( std::optional<int> anchorGroupOpt, RefreshRateOrder, std::optional<DisplayModeId> preferredDisplayModeOpt) const REQUIRES(mLock); RefreshRateRanking rankRefreshRates(std::optional<int> anchorGroupOpt, RefreshRateOrder, std::optional<DisplayModeId> preferredDisplayModeOpt = std::nullopt) const REQUIRES(mLock); const Policy* getCurrentPolicyLocked() const REQUIRES(mLock); bool isPolicyValidLocked(const Policy& policy) const REQUIRES(mLock); Loading Loading @@ -436,7 +461,7 @@ private: struct GetRankedRefreshRatesCache { std::pair<std::vector<LayerRequirement>, GlobalSignals> arguments; std::pair<std::vector<RefreshRateRanking>, GlobalSignals> result; RankedRefreshRates result; }; mutable std::optional<GetRankedRefreshRatesCache> mGetRankedRefreshRatesCache GUARDED_BY(mLock); Loading Loading
libs/ui/include/ui/DisplayId.h +6 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #pragma once #include <cstdint> #include <ostream> #include <string> #include <ftl/optional.h> Loading Loading @@ -67,6 +68,11 @@ inline std::string to_string(DisplayId displayId) { return std::to_string(displayId.value); } // For tests. inline std::ostream& operator<<(std::ostream& stream, DisplayId displayId) { return stream << "DisplayId{" << displayId.value << '}'; } // DisplayId of a physical display, such as the internal display or externally connected display. struct PhysicalDisplayId : DisplayId { static constexpr ftl::Optional<PhysicalDisplayId> tryCast(DisplayId id) { Loading
services/surfaceflinger/Display/DisplayModeRequest.h 0 → 100644 +36 −0 Original line number Diff line number Diff line /* * Copyright 2022 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 <ftl/non_null.h> #include "DisplayHardware/DisplayMode.h" namespace android::display { struct DisplayModeRequest { ftl::NonNull<DisplayModePtr> modePtr; // Whether to emit DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE. bool emitEvent = false; }; inline bool operator==(const DisplayModeRequest& lhs, const DisplayModeRequest& rhs) { return lhs.modePtr == rhs.modePtr && lhs.emitEvent == rhs.emitEvent; } } // namespace android::display
services/surfaceflinger/DisplayDevice.h +13 −1 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ #include <utils/RefBase.h> #include <utils/Timers.h> #include "Display/DisplayModeRequest.h" #include "DisplayHardware/DisplayMode.h" #include "DisplayHardware/Hal.h" #include "DisplayHardware/PowerAdvisor.h" Loading Loading @@ -190,9 +191,20 @@ public: /* ------------------------------------------------------------------------ * Display mode management. */ // TODO(b/241285876): Replace ActiveModeInfo and DisplayModeEvent with DisplayModeRequest. struct ActiveModeInfo { using Event = scheduler::DisplayModeEvent; ActiveModeInfo() = default; ActiveModeInfo(DisplayModePtr mode, Event event) : mode(std::move(mode)), event(event) {} explicit ActiveModeInfo(display::DisplayModeRequest&& request) : ActiveModeInfo(std::move(request.modePtr).take(), request.emitEvent ? Event::Changed : Event::None) {} DisplayModePtr mode; scheduler::DisplayModeEvent event = scheduler::DisplayModeEvent::None; Event event = Event::None; bool operator!=(const ActiveModeInfo& other) const { return mode != other.mode || event != other.event; Loading
services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +35 −45 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include <chrono> #include <cmath> #include <deque> #include <android-base/properties.h> #include <android-base/stringprintf.h> Loading Loading @@ -143,8 +144,7 @@ struct RefreshRateConfigs::RefreshRateScoreComparator { ATRACE_INT(name.c_str(), static_cast<int>(std::round(overallScore * 100))); constexpr float kEpsilon = 0.0001f; if (std::abs(overallScore - rhs.overallScore) > kEpsilon) { if (!ScoredRefreshRate::scoresEqual(overallScore, rhs.overallScore)) { return overallScore > rhs.overallScore; } Loading Loading @@ -288,8 +288,7 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye } auto RefreshRateConfigs::getRankedRefreshRates(const std::vector<LayerRequirement>& layers, GlobalSignals signals) const -> std::pair<std::vector<RefreshRateRanking>, GlobalSignals> { GlobalSignals signals) const -> RankedRefreshRates { std::lock_guard lock(mLock); if (mGetRankedRefreshRatesCache && Loading @@ -304,7 +303,7 @@ auto RefreshRateConfigs::getRankedRefreshRates(const std::vector<LayerRequiremen auto RefreshRateConfigs::getRankedRefreshRatesLocked(const std::vector<LayerRequirement>& layers, GlobalSignals signals) const -> std::pair<std::vector<RefreshRateRanking>, GlobalSignals> { -> RankedRefreshRates { using namespace fps_approx_ops; ATRACE_CALL(); ALOGV("%s: %zu layers", __func__, layers.size()); Loading @@ -314,8 +313,7 @@ auto RefreshRateConfigs::getRankedRefreshRatesLocked(const std::vector<LayerRequ // Keep the display at max refresh rate for the duration of powering on the display. if (signals.powerOnImminent) { ALOGV("Power On Imminent"); return {getRefreshRatesByPolicyLocked(activeMode.getGroup(), RefreshRateOrder::Descending, /*preferredDisplayModeOpt*/ std::nullopt), return {rankRefreshRates(activeMode.getGroup(), RefreshRateOrder::Descending), GlobalSignals{.powerOnImminent = true}}; } Loading Loading @@ -375,8 +373,7 @@ auto RefreshRateConfigs::getRankedRefreshRatesLocked(const std::vector<LayerRequ // selected a refresh rate to see if we should apply touch boost. if (signals.touch && !hasExplicitVoteLayers) { ALOGV("Touch Boost"); return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending, /*preferredDisplayModeOpt*/ std::nullopt), return {rankRefreshRates(anchorGroup, RefreshRateOrder::Descending), GlobalSignals{.touch = true}}; } Loading @@ -388,24 +385,19 @@ auto RefreshRateConfigs::getRankedRefreshRatesLocked(const std::vector<LayerRequ if (!signals.touch && signals.idle && !(primaryRangeIsSingleRate && hasExplicitVoteLayers)) { ALOGV("Idle"); return {getRefreshRatesByPolicyLocked(activeMode.getGroup(), RefreshRateOrder::Ascending, /*preferredDisplayModeOpt*/ std::nullopt), return {rankRefreshRates(activeMode.getGroup(), RefreshRateOrder::Ascending), GlobalSignals{.idle = true}}; } if (layers.empty() || noVoteLayers == layers.size()) { ALOGV("No layers with votes"); return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending, /*preferredDisplayModeOpt*/ std::nullopt), kNoSignals}; return {rankRefreshRates(anchorGroup, RefreshRateOrder::Descending), kNoSignals}; } // Only if all layers want Min we should return Min if (noVoteLayers + minVoteLayers == layers.size()) { ALOGV("All layers Min"); return {getRefreshRatesByPolicyLocked(activeMode.getGroup(), RefreshRateOrder::Ascending, /*preferredDisplayModeOpt*/ std::nullopt), kNoSignals}; return {rankRefreshRates(activeMode.getGroup(), RefreshRateOrder::Ascending), kNoSignals}; } // Find the best refresh rate based on score Loading Loading @@ -557,12 +549,13 @@ auto RefreshRateConfigs::getRankedRefreshRatesLocked(const std::vector<LayerRequ maxVoteLayers > 0 ? RefreshRateOrder::Descending : RefreshRateOrder::Ascending; std::sort(scores.begin(), scores.end(), RefreshRateScoreComparator{.refreshRateOrder = refreshRateOrder}); std::vector<RefreshRateRanking> rankedRefreshRates; rankedRefreshRates.reserve(scores.size()); std::transform(scores.begin(), scores.end(), back_inserter(rankedRefreshRates), RefreshRateRanking ranking; ranking.reserve(scores.size()); std::transform(scores.begin(), scores.end(), back_inserter(ranking), [](const RefreshRateScore& score) { return RefreshRateRanking{score.modeIt->second, score.overallScore}; return ScoredRefreshRate{score.modeIt->second, score.overallScore}; }); const bool noLayerScore = std::all_of(scores.begin(), scores.end(), [](RefreshRateScore score) { Loading @@ -574,11 +567,9 @@ auto RefreshRateConfigs::getRankedRefreshRatesLocked(const std::vector<LayerRequ // range instead of picking a random score from the app range. if (noLayerScore) { ALOGV("Layers not scored"); return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending, /*preferredDisplayModeOpt*/ std::nullopt), kNoSignals}; return {rankRefreshRates(anchorGroup, RefreshRateOrder::Descending), kNoSignals}; } else { return {rankedRefreshRates, kNoSignals}; return {ranking, kNoSignals}; } } Loading @@ -596,14 +587,12 @@ auto RefreshRateConfigs::getRankedRefreshRatesLocked(const std::vector<LayerRequ } }(); const auto& touchRefreshRates = getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending, /*preferredDisplayModeOpt*/ std::nullopt); const auto touchRefreshRates = rankRefreshRates(anchorGroup, RefreshRateOrder::Descending); using fps_approx_ops::operator<; if (signals.touch && explicitDefaultVoteLayers == 0 && touchBoostForExplicitExact && scores.front().modeIt->second->getFps() < touchRefreshRates.front().displayModePtr->getFps()) { scores.front().modeIt->second->getFps() < touchRefreshRates.front().modePtr->getFps()) { ALOGV("Touch Boost"); return {touchRefreshRates, GlobalSignals{.touch = true}}; } Loading @@ -612,12 +601,11 @@ auto RefreshRateConfigs::getRankedRefreshRatesLocked(const std::vector<LayerRequ // current config if (noLayerScore && refreshRateOrder == RefreshRateOrder::Ascending) { const auto preferredDisplayMode = activeMode.getId(); return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Ascending, preferredDisplayMode), return {rankRefreshRates(anchorGroup, RefreshRateOrder::Ascending, preferredDisplayMode), kNoSignals}; } return {rankedRefreshRates, kNoSignals}; return {ranking, kNoSignals}; } std::unordered_map<uid_t, std::vector<const RefreshRateConfigs::LayerRequirement*>> Loading Loading @@ -783,11 +771,12 @@ const DisplayModePtr& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked(int an return mPrimaryRefreshRates.back()->second; } std::vector<RefreshRateRanking> RefreshRateConfigs::getRefreshRatesByPolicyLocked( auto RefreshRateConfigs::rankRefreshRates( std::optional<int> anchorGroupOpt, RefreshRateOrder refreshRateOrder, std::optional<DisplayModeId> preferredDisplayModeOpt) const { std::deque<RefreshRateRanking> rankings; const auto makeRanking = [&](const DisplayModeIterator it) REQUIRES(mLock) { std::optional<DisplayModeId> preferredDisplayModeOpt) const -> RefreshRateRanking { std::deque<ScoredRefreshRate> ranking; const auto rankRefreshRate = [&](DisplayModeIterator it) REQUIRES(mLock) { const auto& mode = it->second; if (anchorGroupOpt && mode->getGroup() != anchorGroupOpt) { return; Loading @@ -800,31 +789,32 @@ std::vector<RefreshRateRanking> RefreshRateConfigs::getRefreshRatesByPolicyLocke } if (preferredDisplayModeOpt) { if (*preferredDisplayModeOpt == mode->getId()) { rankings.push_front(RefreshRateRanking{mode, /*score*/ 1.0f}); constexpr float kScore = std::numeric_limits<float>::max(); ranking.push_front(ScoredRefreshRate{mode, kScore}); return; } constexpr float kNonPreferredModePenalty = 0.95f; score *= kNonPreferredModePenalty; } rankings.push_back(RefreshRateRanking{mode, score}); ranking.push_back(ScoredRefreshRate{mode, score}); }; if (refreshRateOrder == RefreshRateOrder::Ascending) { std::for_each(mPrimaryRefreshRates.begin(), mPrimaryRefreshRates.end(), makeRanking); std::for_each(mPrimaryRefreshRates.begin(), mPrimaryRefreshRates.end(), rankRefreshRate); } else { std::for_each(mPrimaryRefreshRates.rbegin(), mPrimaryRefreshRates.rend(), makeRanking); std::for_each(mPrimaryRefreshRates.rbegin(), mPrimaryRefreshRates.rend(), rankRefreshRate); } if (!rankings.empty() || !anchorGroupOpt) { return {rankings.begin(), rankings.end()}; if (!ranking.empty() || !anchorGroupOpt) { return {ranking.begin(), ranking.end()}; } ALOGW("Can't find %s refresh rate by policy with the same mode group" " as the mode group %d", refreshRateOrder == RefreshRateOrder::Ascending ? "min" : "max", anchorGroupOpt.value()); return getRefreshRatesByPolicyLocked(/*anchorGroupOpt*/ std::nullopt, refreshRateOrder, preferredDisplayModeOpt); constexpr std::optional<int> kNoAnchorGroup = std::nullopt; return rankRefreshRates(kNoAnchorGroup, refreshRateOrder, preferredDisplayModeOpt); } DisplayModePtr RefreshRateConfigs::getActiveModePtr() const { Loading
services/surfaceflinger/Scheduler/RefreshRateConfigs.h +45 −20 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include <utility> #include <variant> #include <ftl/concat.h> #include <gui/DisplayEventReceiver.h> #include <scheduler/Fps.h> Loading @@ -46,15 +47,6 @@ inline DisplayModeEvent operator|(DisplayModeEvent lhs, DisplayModeEvent rhs) { return static_cast<DisplayModeEvent>(static_cast<T>(lhs) | static_cast<T>(rhs)); } struct RefreshRateRanking { DisplayModePtr displayModePtr; float score = 0.0f; bool operator==(const RefreshRateRanking& ranking) const { return displayModePtr == ranking.displayModePtr && score == ranking.score; } }; using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride; /** Loading Loading @@ -208,12 +200,46 @@ public: return touch == other.touch && idle == other.idle && powerOnImminent == other.powerOnImminent; } auto toString() const { return ftl::Concat("{touch=", touch, ", idle=", idle, ", powerOnImminent=", powerOnImminent, '}'); } }; struct ScoredRefreshRate { DisplayModePtr modePtr; float score = 0.0f; bool operator==(const ScoredRefreshRate& other) const { return modePtr == other.modePtr && score == other.score; } static bool scoresEqual(float lhs, float rhs) { constexpr float kEpsilon = 0.0001f; return std::abs(lhs - rhs) <= kEpsilon; } struct DescendingScore { bool operator()(const ScoredRefreshRate& lhs, const ScoredRefreshRate& rhs) const { return lhs.score > rhs.score && !scoresEqual(lhs.score, rhs.score); } }; }; using RefreshRateRanking = std::vector<ScoredRefreshRate>; struct RankedRefreshRates { RefreshRateRanking ranking; // Ordered by descending score. GlobalSignals consideredSignals; bool operator==(const RankedRefreshRates& other) const { return ranking == other.ranking && consideredSignals == other.consideredSignals; } }; // Returns the list in the descending order of refresh rates desired // based on their overall score, and the GlobalSignals that were considered. std::pair<std::vector<RefreshRateRanking>, GlobalSignals> getRankedRefreshRates( const std::vector<LayerRequirement>&, GlobalSignals) const EXCLUDES(mLock); RankedRefreshRates getRankedRefreshRates(const std::vector<LayerRequirement>&, GlobalSignals) const EXCLUDES(mLock); FpsRange getSupportedRefreshRateRange() const EXCLUDES(mLock) { std::lock_guard lock(mLock); Loading Loading @@ -354,8 +380,8 @@ private: // See mActiveModeIt for thread safety. DisplayModeIterator getActiveModeItLocked() const REQUIRES(mLock); std::pair<std::vector<RefreshRateRanking>, GlobalSignals> getRankedRefreshRatesLocked( const std::vector<LayerRequirement>&, GlobalSignals) const REQUIRES(mLock); RankedRefreshRates getRankedRefreshRatesLocked(const std::vector<LayerRequirement>&, GlobalSignals) const REQUIRES(mLock); // Returns number of display frames and remainder when dividing the layer refresh period by // display refresh period. Loading @@ -373,11 +399,10 @@ private: enum class RefreshRateOrder { Ascending, Descending }; // Returns the rankings in RefreshRateOrder. May change at runtime. // Only uses the primary range, not the app request range. std::vector<RefreshRateRanking> getRefreshRatesByPolicyLocked( std::optional<int> anchorGroupOpt, RefreshRateOrder, std::optional<DisplayModeId> preferredDisplayModeOpt) const REQUIRES(mLock); RefreshRateRanking rankRefreshRates(std::optional<int> anchorGroupOpt, RefreshRateOrder, std::optional<DisplayModeId> preferredDisplayModeOpt = std::nullopt) const REQUIRES(mLock); const Policy* getCurrentPolicyLocked() const REQUIRES(mLock); bool isPolicyValidLocked(const Policy& policy) const REQUIRES(mLock); Loading Loading @@ -436,7 +461,7 @@ private: struct GetRankedRefreshRatesCache { std::pair<std::vector<LayerRequirement>, GlobalSignals> arguments; std::pair<std::vector<RefreshRateRanking>, GlobalSignals> result; RankedRefreshRates result; }; mutable std::optional<GetRankedRefreshRatesCache> mGetRankedRefreshRatesCache GUARDED_BY(mLock); Loading