diff options
16 files changed, 530 insertions, 417 deletions
diff --git a/libs/ui/include/ui/DisplayId.h b/libs/ui/include/ui/DisplayId.h index d0c03fe39f..3a31fa0848 100644 --- a/libs/ui/include/ui/DisplayId.h +++ b/libs/ui/include/ui/DisplayId.h @@ -17,6 +17,7 @@ #pragma once #include <cstdint> +#include <ostream> #include <string> #include <ftl/optional.h> @@ -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) { diff --git a/services/surfaceflinger/Display/DisplayModeRequest.h b/services/surfaceflinger/Display/DisplayModeRequest.h new file mode 100644 index 0000000000..ac25fe08a5 --- /dev/null +++ b/services/surfaceflinger/Display/DisplayModeRequest.h @@ -0,0 +1,36 @@ +/* + * 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 diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 06a812b6f4..7abb94b84f 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -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" @@ -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; diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index 30483a2aff..39850c7e1e 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -23,6 +23,7 @@ #include <chrono> #include <cmath> +#include <deque> #include <android-base/properties.h> #include <android-base/stringprintf.h> @@ -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; } @@ -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 && @@ -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()); @@ -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}}; } @@ -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}}; } @@ -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 @@ -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) { @@ -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}; } } @@ -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}}; } @@ -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*>> @@ -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; @@ -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 { diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index 721958480b..99f81aa75e 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -23,6 +23,7 @@ #include <utility> #include <variant> +#include <ftl/concat.h> #include <gui/DisplayEventReceiver.h> #include <scheduler/Fps.h> @@ -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; /** @@ -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); @@ -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. @@ -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); @@ -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); diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 30f2c27b1e..be3ebb7947 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -127,11 +127,19 @@ void Scheduler::setRefreshRateConfigs(std::shared_ptr<RefreshRateConfigs> config } void Scheduler::registerDisplay(sp<const DisplayDevice> display) { + if (display->isPrimary()) { + mLeaderDisplayId = display->getPhysicalId(); + } + const bool ok = mDisplays.try_emplace(display->getPhysicalId(), std::move(display)).second; ALOGE_IF(!ok, "%s: Duplicate display", __func__); } void Scheduler::unregisterDisplay(PhysicalDisplayId displayId) { + if (mLeaderDisplayId == displayId) { + mLeaderDisplayId.reset(); + } + mDisplays.erase(displayId); } @@ -631,9 +639,8 @@ bool Scheduler::updateFrameRateOverrides(GlobalSignals consideredSignals, Fps di template <typename S, typename T> auto Scheduler::applyPolicy(S Policy::*statePtr, T&& newState) -> GlobalSignals { - DisplayModePtr newMode; + std::vector<display::DisplayModeRequest> modeRequests; GlobalSignals consideredSignals; - std::vector<DisplayModeConfig> displayModeConfigs; bool refreshRateChanged = false; bool frameRateOverridesChanged; @@ -646,42 +653,41 @@ auto Scheduler::applyPolicy(S Policy::*statePtr, T&& newState) -> GlobalSignals if (currentState == newState) return {}; currentState = std::forward<T>(newState); - displayModeConfigs = getBestDisplayModeConfigs(); - - // mPolicy holds the current mode, using the current mode we find out - // what display is currently being tracked through the policy and - // then find the DisplayModeConfig for that display. So that - // later we check if the policy mode has changed for the same display in policy. - // If mPolicy mode isn't available then we take the first display from the best display - // modes as the candidate for policy changes and frame rate overrides. - // TODO(b/240743786) Update the single display based assumptions and make mode changes - // and mPolicy per display. - const DisplayModeConfig& displayModeConfigForCurrentPolicy = mPolicy.mode - ? *std::find_if(displayModeConfigs.begin(), displayModeConfigs.end(), - [&](const auto& displayModeConfig) REQUIRES(mPolicyLock) { - return displayModeConfig.displayModePtr - ->getPhysicalDisplayId() == - mPolicy.mode->getPhysicalDisplayId(); - }) - : displayModeConfigs.front(); - - newMode = displayModeConfigForCurrentPolicy.displayModePtr; - consideredSignals = displayModeConfigForCurrentPolicy.signals; - frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps()); - - if (mPolicy.mode == newMode) { + auto modeChoices = chooseDisplayModes(); + + // TODO(b/240743786): The leader display's mode must change for any DisplayModeRequest to go + // through. Fix this by tracking per-display Scheduler::Policy and timers. + DisplayModePtr modePtr; + std::tie(modePtr, consideredSignals) = + modeChoices.get(*mLeaderDisplayId) + .transform([](const DisplayModeChoice& choice) { + return std::make_pair(choice.modePtr, choice.consideredSignals); + }) + .value(); + + modeRequests.reserve(modeChoices.size()); + for (auto& [id, choice] : modeChoices) { + modeRequests.emplace_back( + display::DisplayModeRequest{.modePtr = + ftl::as_non_null(std::move(choice.modePtr)), + .emitEvent = !choice.consideredSignals.idle}); + } + + frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, modePtr->getFps()); + + if (mPolicy.mode != modePtr) { + mPolicy.mode = modePtr; + refreshRateChanged = true; + } else { // We don't need to change the display mode, but we might need to send an event // about a mode change, since it was suppressed if previously considered idle. if (!consideredSignals.idle) { dispatchCachedReportedMode(); } - } else { - mPolicy.mode = newMode; - refreshRateChanged = true; } } if (refreshRateChanged) { - mSchedulerCallback.requestDisplayModes(std::move(displayModeConfigs)); + mSchedulerCallback.requestDisplayModes(std::move(modeRequests)); } if (frameRateOverridesChanged) { mSchedulerCallback.triggerOnFrameRateOverridesChanged(); @@ -689,11 +695,11 @@ auto Scheduler::applyPolicy(S Policy::*statePtr, T&& newState) -> GlobalSignals return consideredSignals; } -std::vector<DisplayModeConfig> Scheduler::getBestDisplayModeConfigs() const { +auto Scheduler::chooseDisplayModes() const -> DisplayModeChoiceMap { ATRACE_CALL(); - using Rankings = std::pair<std::vector<RefreshRateRanking>, GlobalSignals>; - display::PhysicalDisplayVector<Rankings> perDisplayRankings; + using RankedRefreshRates = RefreshRateConfigs::RankedRefreshRates; + display::PhysicalDisplayVector<RankedRefreshRates> perDisplayRanking; // Tallies the score of a refresh rate across `displayCount` displays. struct RefreshRateTally { @@ -710,11 +716,11 @@ std::vector<DisplayModeConfig> Scheduler::getBestDisplayModeConfigs() const { const auto globalSignals = makeGlobalSignals(); for (const auto& [id, display] : mDisplays) { - auto [rankings, signals] = + auto rankedRefreshRates = display->holdRefreshRateConfigs() ->getRankedRefreshRates(mPolicy.contentRequirements, globalSignals); - for (const auto& [modePtr, score] : rankings) { + for (const auto& [modePtr, score] : rankedRefreshRates.ranking) { const auto [it, inserted] = refreshRateTallies.try_emplace(modePtr->getFps(), score); if (!inserted) { @@ -724,7 +730,7 @@ std::vector<DisplayModeConfig> Scheduler::getBestDisplayModeConfigs() const { } } - perDisplayRankings.emplace_back(std::move(rankings), signals); + perDisplayRanking.push_back(std::move(rankedRefreshRates)); } auto maxScoreIt = refreshRateTallies.cbegin(); @@ -750,26 +756,27 @@ std::vector<DisplayModeConfig> Scheduler::getBestDisplayModeConfigs() const { ? std::make_optional(maxScoreIt->first) : std::nullopt; - std::vector<DisplayModeConfig> displayModeConfigs; - displayModeConfigs.reserve(mDisplays.size()); + DisplayModeChoiceMap modeChoices; using fps_approx_ops::operator==; - for (const auto& [rankings, signals] : perDisplayRankings) { + for (auto& [ranking, signals] : perDisplayRanking) { if (!chosenFps) { - displayModeConfigs.emplace_back(signals, rankings.front().displayModePtr); + auto& [modePtr, _] = ranking.front(); + modeChoices.try_emplace(modePtr->getPhysicalDisplayId(), + DisplayModeChoice{std::move(modePtr), signals}); continue; } - for (const auto& ranking : rankings) { - const auto& modePtr = ranking.displayModePtr; + for (auto& [modePtr, _] : ranking) { if (modePtr->getFps() == *chosenFps) { - displayModeConfigs.emplace_back(signals, modePtr); + modeChoices.try_emplace(modePtr->getPhysicalDisplayId(), + DisplayModeChoice{std::move(modePtr), signals}); break; } } } - return displayModeConfigs; + return modeChoices; } GlobalSignals Scheduler::makeGlobalSignals() const { @@ -787,11 +794,11 @@ DisplayModePtr Scheduler::getPreferredDisplayMode() { // Make sure the stored mode is up to date. if (mPolicy.mode) { const auto configs = holdRefreshRateConfigs(); - const auto rankings = + const auto ranking = configs->getRankedRefreshRates(mPolicy.contentRequirements, makeGlobalSignals()) - .first; + .ranking; - mPolicy.mode = rankings.front().displayModePtr; + mPolicy.mode = ranking.front().modePtr; } return mPolicy.mode; } diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 6633b0500a..33f612632b 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -38,6 +38,7 @@ #include <ui/DisplayId.h> #include "Display/DisplayMap.h" +#include "Display/DisplayModeRequest.h" #include "DisplayDevice.h" #include "EventThread.h" #include "FrameRateOverrideMappings.h" @@ -88,20 +89,9 @@ namespace scheduler { using GlobalSignals = RefreshRateConfigs::GlobalSignals; -// Config representing the DisplayMode and considered signals for the Display. -struct DisplayModeConfig { - const GlobalSignals signals; - const DisplayModePtr displayModePtr; - - DisplayModeConfig(GlobalSignals signals, DisplayModePtr displayModePtr) - : signals(signals), displayModePtr(std::move(displayModePtr)) {} -}; - struct ISchedulerCallback { - using DisplayModeEvent = scheduler::DisplayModeEvent; - virtual void setVsyncEnabled(bool) = 0; - virtual void requestDisplayModes(std::vector<DisplayModeConfig>) = 0; + virtual void requestDisplayModes(std::vector<display::DisplayModeRequest>) = 0; virtual void kernelTimerChanged(bool expired) = 0; virtual void triggerOnFrameRateOverridesChanged() = 0; @@ -278,8 +268,26 @@ private: template <typename S, typename T> GlobalSignals applyPolicy(S Policy::*, T&&) EXCLUDES(mPolicyLock); - // Returns the best display mode per display. - std::vector<DisplayModeConfig> getBestDisplayModeConfigs() const REQUIRES(mPolicyLock); + struct DisplayModeChoice { + DisplayModeChoice(DisplayModePtr modePtr, GlobalSignals consideredSignals) + : modePtr(std::move(modePtr)), consideredSignals(consideredSignals) {} + + DisplayModePtr modePtr; + GlobalSignals consideredSignals; + + bool operator==(const DisplayModeChoice& other) const { + return modePtr == other.modePtr && consideredSignals == other.consideredSignals; + } + + // For tests. + friend std::ostream& operator<<(std::ostream& stream, const DisplayModeChoice& choice) { + return stream << '{' << to_string(*choice.modePtr) << " considering " + << choice.consideredSignals.toString().c_str() << '}'; + } + }; + + using DisplayModeChoiceMap = display::PhysicalDisplayMap<PhysicalDisplayId, DisplayModeChoice>; + DisplayModeChoiceMap chooseDisplayModes() const REQUIRES(mPolicyLock); GlobalSignals makeGlobalSignals() const REQUIRES(mPolicyLock); @@ -329,6 +337,7 @@ private: mutable std::mutex mPolicyLock; display::PhysicalDisplayMap<PhysicalDisplayId, sp<const DisplayDevice>> mDisplays; + std::optional<PhysicalDisplayId> mLeaderDisplayId; struct Policy { // Policy for choosing the display mode. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 52e85421b6..c1eda1793d 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1064,30 +1064,28 @@ status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>&, DisplayStatInfo* ou return NO_ERROR; } -void SurfaceFlinger::setDesiredActiveMode(const ActiveModeInfo& info) { +void SurfaceFlinger::setDesiredActiveMode(display::DisplayModeRequest&& request) { ATRACE_CALL(); - if (!info.mode) { - ALOGW("requested display mode is null"); - return; - } - auto display = getDisplayDeviceLocked(info.mode->getPhysicalDisplayId()); + auto display = getDisplayDeviceLocked(request.modePtr->getPhysicalDisplayId()); if (!display) { ALOGW("%s: display is no longer valid", __func__); return; } - if (display->setDesiredActiveMode(info)) { + const Fps refreshRate = request.modePtr->getFps(); + + if (display->setDesiredActiveMode(DisplayDevice::ActiveModeInfo(std::move(request)))) { scheduleComposite(FrameHint::kNone); // Start receiving vsync samples now, so that we can detect a period // switch. - mScheduler->resyncToHardwareVsync(true, info.mode->getFps()); + mScheduler->resyncToHardwareVsync(true, refreshRate); // As we called to set period, we will call to onRefreshRateChangeCompleted once // VsyncController model is locked. modulateVsync(&VsyncModulator::onRefreshRateChangeInitiated); - updatePhaseConfiguration(info.mode->getFps()); + updatePhaseConfiguration(refreshRate); mScheduler->setModeChangePending(true); } } @@ -1179,7 +1177,7 @@ void SurfaceFlinger::updateInternalStateWithChangedMode() { mRefreshRateStats->setRefreshRate(refreshRate); updatePhaseConfiguration(refreshRate); - if (upcomingModeInfo.event != DisplayModeEvent::None) { + if (upcomingModeInfo.event != scheduler::DisplayModeEvent::None) { mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, upcomingModeInfo.mode); } } @@ -3331,34 +3329,33 @@ void SurfaceFlinger::updateCursorAsync() { mCompositionEngine->updateCursorAsync(refreshArgs); } -void SurfaceFlinger::requestDisplayModes( - std::vector<scheduler::DisplayModeConfig> displayModeConfigs) { +void SurfaceFlinger::requestDisplayModes(std::vector<display::DisplayModeRequest> modeRequests) { if (mBootStage != BootStage::FINISHED) { ALOGV("Currently in the boot stage, skipping display mode changes"); return; } ATRACE_CALL(); + // If this is called from the main thread mStateLock must be locked before // Currently the only way to call this function from the main thread is from // Scheduler::chooseRefreshRateForContent ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId); - std::for_each(displayModeConfigs.begin(), displayModeConfigs.end(), - [&](const auto& config) REQUIRES(mStateLock) { - const auto& displayModePtr = config.displayModePtr; - if (const auto display = - getDisplayDeviceLocked(displayModePtr->getPhysicalDisplayId()); - display->refreshRateConfigs().isModeAllowed(displayModePtr->getId())) { - const auto event = config.signals.idle ? DisplayModeEvent::None - : DisplayModeEvent::Changed; - setDesiredActiveMode({displayModePtr, event}); - } else { - ALOGV("Skipping disallowed mode %d for display %" PRId64, - displayModePtr->getId().value(), display->getPhysicalId().value); - } - }); + for (auto& request : modeRequests) { + const auto& modePtr = request.modePtr; + const auto display = getDisplayDeviceLocked(modePtr->getPhysicalDisplayId()); + + if (!display) continue; + + if (display->refreshRateConfigs().isModeAllowed(modePtr->getId())) { + setDesiredActiveMode(std::move(request)); + } else { + ALOGV("%s: Mode %d is disallowed for display %s", __func__, modePtr->getId().value(), + to_string(display->getId()).c_str()); + } + } } void SurfaceFlinger::triggerOnFrameRateOverridesChanged() { @@ -6584,18 +6581,19 @@ void SurfaceFlinger::traverseLayersInLayerStack(ui::LayerStack layerStack, const } } -std::optional<DisplayModePtr> SurfaceFlinger::getPreferredDisplayMode( +std::optional<ftl::NonNull<DisplayModePtr>> SurfaceFlinger::getPreferredDisplayMode( PhysicalDisplayId displayId, DisplayModeId defaultModeId) const { if (const auto schedulerMode = mScheduler->getPreferredDisplayMode(); schedulerMode && schedulerMode->getPhysicalDisplayId() == displayId) { - return schedulerMode; + return ftl::as_non_null(schedulerMode); } return mPhysicalDisplays.get(displayId) .transform(&PhysicalDisplay::snapshotRef) .and_then([&](const display::DisplaySnapshot& snapshot) { return snapshot.displayModes().get(defaultModeId); - }); + }) + .transform(&ftl::as_non_null<const DisplayModePtr&>); } status_t SurfaceFlinger::setDesiredDisplayModeSpecsInternal( @@ -6651,7 +6649,7 @@ status_t SurfaceFlinger::setDesiredDisplayModeSpecsInternal( return INVALID_OPERATION; } - setDesiredActiveMode({std::move(preferredMode), DisplayModeEvent::Changed}); + setDesiredActiveMode({std::move(preferredMode), .emitEvent = true}); return NO_ERROR; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index b65dec4dfe..9ffe6abbe6 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -29,6 +29,7 @@ #include <cutils/atomic.h> #include <cutils/compiler.h> #include <ftl/future.h> +#include <ftl/non_null.h> #include <gui/BufferQueue.h> #include <gui/CompositorTiming.h> #include <gui/FrameTimestamps.h> @@ -430,10 +431,6 @@ private: mCounterByLayerHandle GUARDED_BY(mLock); }; - using ActiveModeInfo = DisplayDevice::ActiveModeInfo; - using KernelIdleTimerController = - ::android::scheduler::RefreshRateConfigs::KernelIdleTimerController; - enum class BootStage { BOOTLOADER, BOOTANIMATION, @@ -628,16 +625,17 @@ private: // ISchedulerCallback overrides: // Toggles hardware VSYNC by calling into HWC. + // TODO(b/241286146): Rename for self-explanatory API. void setVsyncEnabled(bool) override; - // Sets the desired display mode per display if allowed by policy . - void requestDisplayModes(std::vector<scheduler::DisplayModeConfig>) override; - // Called when kernel idle timer has expired. Used to update the refresh rate overlay. + void requestDisplayModes(std::vector<display::DisplayModeRequest>) override; void kernelTimerChanged(bool expired) override; - // Called when the frame rate override list changed to trigger an event. void triggerOnFrameRateOverridesChanged() override; // Toggles the kernel idle timer on or off depending the policy decisions around refresh rates. void toggleKernelIdleTimer() REQUIRES(mStateLock); + + using KernelIdleTimerController = scheduler::RefreshRateConfigs::KernelIdleTimerController; + // Get the controller and timeout that will help decide how the kernel idle timer will be // configured and what value to use as the timeout. std::pair<std::optional<KernelIdleTimerController>, std::chrono::milliseconds> @@ -652,8 +650,8 @@ private: // Show spinner with refresh rate overlay bool mRefreshRateOverlaySpinner = false; - // Sets the desired active mode bit. It obtains the lock, and sets mDesiredActiveMode. - void setDesiredActiveMode(const ActiveModeInfo& info) REQUIRES(mStateLock); + void setDesiredActiveMode(display::DisplayModeRequest&&) REQUIRES(mStateLock); + status_t setActiveModeFromBackdoor(const sp<display::DisplayToken>&, DisplayModeId); // Sets the active mode and a new refresh rate in SF. void updateInternalStateWithChangedMode() REQUIRES(mStateLock, kMainThreadContext); @@ -672,9 +670,8 @@ private: // Returns the preferred mode for PhysicalDisplayId if the Scheduler has selected one for that // display. Falls back to the display's defaultModeId otherwise. - std::optional<DisplayModePtr> getPreferredDisplayMode(PhysicalDisplayId, - DisplayModeId defaultModeId) const - REQUIRES(mStateLock); + std::optional<ftl::NonNull<DisplayModePtr>> getPreferredDisplayMode( + PhysicalDisplayId, DisplayModeId defaultModeId) const REQUIRES(mStateLock); status_t setDesiredDisplayModeSpecsInternal(const sp<DisplayDevice>&, const scheduler::RefreshRateConfigs::PolicyVariant&) diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h index e2ae4f4d7f..99279dce8b 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h +++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h @@ -780,7 +780,7 @@ public: private: void setVsyncEnabled(bool) override {} - void requestDisplayModes(std::vector<scheduler::DisplayModeConfig>) override {} + void requestDisplayModes(std::vector<display::DisplayModeRequest>) override {} void kernelTimerChanged(bool) override {} void triggerOnFrameRateOverridesChanged() override {} diff --git a/services/surfaceflinger/tests/unittests/FakeDisplayInjector.h b/services/surfaceflinger/tests/unittests/FakeDisplayInjector.h index 6ee4b9bf66..6e4bf2b06e 100644 --- a/services/surfaceflinger/tests/unittests/FakeDisplayInjector.h +++ b/services/surfaceflinger/tests/unittests/FakeDisplayInjector.h @@ -29,7 +29,7 @@ using android::hardware::graphics::composer::hal::HWDisplayId; using android::Hwc2::mock::PowerAdvisor; struct FakeDisplayInjectorArgs { - uint8_t port = 255u; + PhysicalDisplayId displayId = PhysicalDisplayId::fromPort(255u); HWDisplayId hwcDisplayId = 0; bool isPrimary = true; }; @@ -67,7 +67,7 @@ public: auto compositionDisplay = compositionengine::impl:: createDisplay(mFlinger.getCompositionEngine(), compositionengine::DisplayCreationArgsBuilder() - .setId(PhysicalDisplayId::fromPort(args.port)) + .setId(args.displayId) .setPixels(kResolution) .setPowerAdvisor(&mPowerAdvisor) .build()); diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index 620825f066..924c5befde 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -17,6 +17,9 @@ #undef LOG_TAG #define LOG_TAG "SchedulerUnittests" +#include <algorithm> +#include <array> + #include <ftl/enum.h> #include <ftl/fake_guard.h> #include <gmock/gmock.h> @@ -34,15 +37,17 @@ namespace android::scheduler { namespace hal = android::hardware::graphics::composer::hal; -using SetPolicyResult = RefreshRateConfigs::SetPolicyResult; -using LayerVoteType = RefreshRateConfigs::LayerVoteType; using LayerRequirement = RefreshRateConfigs::LayerRequirement; +using LayerVoteType = RefreshRateConfigs::LayerVoteType; +using SetPolicyResult = RefreshRateConfigs::SetPolicyResult; using mock::createDisplayMode; struct TestableRefreshRateConfigs : RefreshRateConfigs { - using RefreshRateConfigs::RefreshRateConfigs; using RefreshRateConfigs::RefreshRateOrder; + using RefreshRateConfigs::RefreshRateRanking; + + using RefreshRateConfigs::RefreshRateConfigs; void setActiveModeId(DisplayModeId modeId) { ftl::FakeGuard guard(kMainThreadContext); @@ -74,12 +79,10 @@ struct TestableRefreshRateConfigs : RefreshRateConfigs { return getMaxRefreshRateByPolicyLocked(getActiveModeItLocked()->second->getGroup()); } - std::vector<RefreshRateRanking> getRefreshRatesByPolicy( - std::optional<int> anchorGroupOpt, RefreshRateOrder refreshRateOrder) const { + RefreshRateRanking rankRefreshRates(std::optional<int> anchorGroupOpt, + RefreshRateOrder refreshRateOrder) const { std::lock_guard lock(mLock); - return RefreshRateConfigs:: - getRefreshRatesByPolicyLocked(anchorGroupOpt, refreshRateOrder, - /*preferredDisplayModeOpt*/ std::nullopt); + return RefreshRateConfigs::rankRefreshRates(anchorGroupOpt, refreshRateOrder); } const std::vector<Fps>& knownFrameRates() const { return mKnownFrameRates; } @@ -87,14 +90,25 @@ struct TestableRefreshRateConfigs : RefreshRateConfigs { using RefreshRateConfigs::GetRankedRefreshRatesCache; auto& mutableGetRankedRefreshRatesCache() { return mGetRankedRefreshRatesCache; } - auto getRankedRefreshRatesAndSignals(const std::vector<LayerRequirement>& layers, - GlobalSignals signals) const { - return RefreshRateConfigs::getRankedRefreshRates(layers, signals); + auto getRankedRefreshRates(const std::vector<LayerRequirement>& layers, + GlobalSignals signals) const { + const auto result = RefreshRateConfigs::getRankedRefreshRates(layers, signals); + + EXPECT_TRUE(std::is_sorted(result.ranking.begin(), result.ranking.end(), + ScoredRefreshRate::DescendingScore{})); + + return result; + } + + auto getRankedRefreshRatesAsPair(const std::vector<LayerRequirement>& layers, + GlobalSignals signals) const { + const auto [ranking, consideredSignals] = getRankedRefreshRates(layers, signals); + return std::make_pair(ranking, consideredSignals); } DisplayModePtr getBestRefreshRate(const std::vector<LayerRequirement>& layers = {}, GlobalSignals signals = {}) const { - return getRankedRefreshRatesAndSignals(layers, signals).first.front().displayModePtr; + return getRankedRefreshRates(layers, signals).ranking.front().modePtr; } SetPolicyResult setPolicy(const PolicyVariant& policy) { @@ -109,6 +123,8 @@ struct TestableRefreshRateConfigs : RefreshRateConfigs { class RefreshRateConfigsTest : public testing::Test { protected: + using RefreshRateOrder = TestableRefreshRateConfigs::RefreshRateOrder; + RefreshRateConfigsTest(); ~RefreshRateConfigsTest(); @@ -1050,20 +1066,17 @@ TEST_F(RefreshRateConfigsTest, getMaxRefreshRatesByPolicy) { // The kModes_30_60_90 contains two kMode72_G1, kMode120_G1 which are from the // different group. TestableRefreshRateConfigs configs(kModes_30_60_90, kModeId60); - const std::vector<RefreshRateRanking>& expectedRefreshRates = {RefreshRateRanking{kMode90}, - RefreshRateRanking{kMode60}, - RefreshRateRanking{kMode30}}; - const std::vector<RefreshRateRanking>& refreshRates = - configs.getRefreshRatesByPolicy(configs.getActiveMode().getGroup(), - TestableRefreshRateConfigs::RefreshRateOrder:: - Descending); + const auto refreshRates = configs.rankRefreshRates(configs.getActiveMode().getGroup(), + RefreshRateOrder::Descending); + const std::array expectedRefreshRates = {kMode90, kMode60, kMode30}; ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size()); + for (size_t i = 0; i < expectedRefreshRates.size(); ++i) { - EXPECT_EQ(expectedRefreshRates[i].displayModePtr, refreshRates[i].displayModePtr) - << "Expected fps " << expectedRefreshRates[i].displayModePtr->getFps().getIntValue() - << " Actual fps " << refreshRates[i].displayModePtr->getFps().getIntValue(); + EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].modePtr) + << "Expected fps " << expectedRefreshRates[i]->getFps().getIntValue() + << " Actual fps " << refreshRates[i].modePtr->getFps().getIntValue(); } } @@ -1071,20 +1084,17 @@ TEST_F(RefreshRateConfigsTest, getMinRefreshRatesByPolicy) { // The kModes_30_60_90 contains two kMode72_G1, kMode120_G1 which are from the // different group. TestableRefreshRateConfigs configs(kModes_30_60_90, kModeId60); - const std::vector<RefreshRateRanking>& expectedRefreshRates = {RefreshRateRanking{kMode30}, - RefreshRateRanking{kMode60}, - RefreshRateRanking{kMode90}}; - const std::vector<RefreshRateRanking>& refreshRates = - configs.getRefreshRatesByPolicy(configs.getActiveMode().getGroup(), - TestableRefreshRateConfigs::RefreshRateOrder:: - Ascending); + const auto refreshRates = configs.rankRefreshRates(configs.getActiveMode().getGroup(), + RefreshRateOrder::Ascending); + const std::array expectedRefreshRates = {kMode30, kMode60, kMode90}; ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size()); + for (size_t i = 0; i < expectedRefreshRates.size(); ++i) { - EXPECT_EQ(expectedRefreshRates[i].displayModePtr, refreshRates[i].displayModePtr) - << "Expected fps " << expectedRefreshRates[i].displayModePtr->getFps().getIntValue() - << " Actual fps " << refreshRates[i].displayModePtr->getFps().getIntValue(); + EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].modePtr) + << "Expected fps " << expectedRefreshRates[i]->getFps().getIntValue() + << " Actual fps " << refreshRates[i].modePtr->getFps().getIntValue(); } } @@ -1092,23 +1102,20 @@ TEST_F(RefreshRateConfigsTest, getMinRefreshRatesByPolicyOutsideTheGroup) { // The kModes_30_60_90 contains two kMode72_G1, kMode120_G1 which are from the // different group. TestableRefreshRateConfigs configs(kModes_30_60_90, kModeId72); - const std::vector<RefreshRateRanking>& expectedRefreshRates = {RefreshRateRanking{kMode30}, - RefreshRateRanking{kMode60}, - RefreshRateRanking{kMode90}}; EXPECT_EQ(SetPolicyResult::Changed, configs.setDisplayManagerPolicy({kModeId60, {30_Hz, 90_Hz}, {30_Hz, 90_Hz}})); - const std::vector<RefreshRateRanking>& refreshRates = - configs.getRefreshRatesByPolicy(/*anchorGroupOpt*/ std::nullopt, - TestableRefreshRateConfigs::RefreshRateOrder:: - Ascending); + const auto refreshRates = + configs.rankRefreshRates(/*anchorGroupOpt*/ std::nullopt, RefreshRateOrder::Ascending); + const std::array expectedRefreshRates = {kMode30, kMode60, kMode90}; ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size()); + for (size_t i = 0; i < expectedRefreshRates.size(); ++i) { - EXPECT_EQ(expectedRefreshRates[i].displayModePtr, refreshRates[i].displayModePtr) - << "Expected fps " << expectedRefreshRates[i].displayModePtr->getFps().getIntValue() - << " Actual fps " << refreshRates[i].displayModePtr->getFps().getIntValue(); + EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].modePtr) + << "Expected fps " << expectedRefreshRates[i]->getFps().getIntValue() + << " Actual fps " << refreshRates[i].modePtr->getFps().getIntValue(); } } @@ -1116,47 +1123,48 @@ TEST_F(RefreshRateConfigsTest, getMaxRefreshRatesByPolicyOutsideTheGroup) { // The kModes_30_60_90 contains two kMode72_G1, kMode120_G1 which are from the // different group. TestableRefreshRateConfigs configs(kModes_30_60_90, kModeId72); - const std::vector<RefreshRateRanking>& expectedRefreshRates = {RefreshRateRanking{kMode90}, - RefreshRateRanking{kMode60}, - RefreshRateRanking{kMode30}}; EXPECT_EQ(SetPolicyResult::Changed, configs.setDisplayManagerPolicy({kModeId60, {30_Hz, 90_Hz}, {30_Hz, 90_Hz}})); - const std::vector<RefreshRateRanking>& refreshRates = - configs.getRefreshRatesByPolicy(/*anchorGroupOpt*/ std::nullopt, - TestableRefreshRateConfigs::RefreshRateOrder:: - Descending); + const auto refreshRates = + configs.rankRefreshRates(/*anchorGroupOpt*/ std::nullopt, RefreshRateOrder::Descending); + const std::array expectedRefreshRates = {kMode90, kMode60, kMode30}; ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size()); + for (size_t i = 0; i < expectedRefreshRates.size(); ++i) { - EXPECT_EQ(expectedRefreshRates[i].displayModePtr, refreshRates[i].displayModePtr) - << "Expected fps " << expectedRefreshRates[i].displayModePtr->getFps().getIntValue() - << " Actual fps " << refreshRates[i].displayModePtr->getFps().getIntValue(); + EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].modePtr) + << "Expected fps " << expectedRefreshRates[i]->getFps().getIntValue() + << " Actual fps " << refreshRates[i].modePtr->getFps().getIntValue(); } } TEST_F(RefreshRateConfigsTest, powerOnImminentConsidered) { - RefreshRateConfigs configs(kModes_60_90, kModeId60); - std::vector<RefreshRateRanking> expectedRefreshRates = {RefreshRateRanking{kMode90}, - RefreshRateRanking{kMode60}}; + TestableRefreshRateConfigs configs(kModes_60_90, kModeId60); auto [refreshRates, signals] = configs.getRankedRefreshRates({}, {}); EXPECT_FALSE(signals.powerOnImminent); + + std::array expectedRefreshRates = {kMode90, kMode60}; ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size()); + for (size_t i = 0; i < expectedRefreshRates.size(); ++i) { - EXPECT_EQ(expectedRefreshRates[i].displayModePtr, refreshRates[i].displayModePtr) - << "Expected fps " << expectedRefreshRates[i].displayModePtr->getFps().getIntValue() - << " Actual fps " << refreshRates[i].displayModePtr->getFps().getIntValue(); + EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].modePtr) + << "Expected fps " << expectedRefreshRates[i]->getFps().getIntValue() + << " Actual fps " << refreshRates[i].modePtr->getFps().getIntValue(); } - std::tie(refreshRates, signals) = configs.getRankedRefreshRates({}, {.powerOnImminent = true}); + std::tie(refreshRates, signals) = + configs.getRankedRefreshRatesAsPair({}, {.powerOnImminent = true}); EXPECT_TRUE(signals.powerOnImminent); + ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size()); + for (size_t i = 0; i < expectedRefreshRates.size(); ++i) { - EXPECT_EQ(expectedRefreshRates[i].displayModePtr, refreshRates[i].displayModePtr) - << "Expected fps " << expectedRefreshRates[i].displayModePtr->getFps().getIntValue() - << " Actual fps " << refreshRates[i].displayModePtr->getFps().getIntValue(); + EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].modePtr) + << "Expected fps " << expectedRefreshRates[i]->getFps().getIntValue() + << " Actual fps " << refreshRates[i].modePtr->getFps().getIntValue(); } std::vector<LayerRequirement> layers = {{.weight = 1.f}}; @@ -1166,34 +1174,38 @@ TEST_F(RefreshRateConfigsTest, powerOnImminentConsidered) { lr1.name = "60Hz ExplicitExactOrMultiple"; std::tie(refreshRates, signals) = - configs.getRankedRefreshRates(layers, {.powerOnImminent = true}); + configs.getRankedRefreshRatesAsPair(layers, {.powerOnImminent = true}); EXPECT_TRUE(signals.powerOnImminent); + ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size()); + for (size_t i = 0; i < expectedRefreshRates.size(); ++i) { - EXPECT_EQ(expectedRefreshRates[i].displayModePtr, refreshRates[i].displayModePtr) - << "Expected fps " << expectedRefreshRates[i].displayModePtr->getFps().getIntValue() - << " Actual fps " << refreshRates[i].displayModePtr->getFps().getIntValue(); + EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].modePtr) + << "Expected fps " << expectedRefreshRates[i]->getFps().getIntValue() + << " Actual fps " << refreshRates[i].modePtr->getFps().getIntValue(); } - expectedRefreshRates = {RefreshRateRanking{kMode60}, RefreshRateRanking{kMode90}}; std::tie(refreshRates, signals) = - configs.getRankedRefreshRates(layers, {.powerOnImminent = false}); + configs.getRankedRefreshRatesAsPair(layers, {.powerOnImminent = false}); EXPECT_FALSE(signals.powerOnImminent); + + expectedRefreshRates = {kMode60, kMode90}; ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size()); + for (size_t i = 0; i < expectedRefreshRates.size(); ++i) { - EXPECT_EQ(expectedRefreshRates[i].displayModePtr, refreshRates[i].displayModePtr) - << "Expected fps " << expectedRefreshRates[i].displayModePtr->getFps().getIntValue() - << " Actual fps " << refreshRates[i].displayModePtr->getFps().getIntValue(); + EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].modePtr) + << "Expected fps " << expectedRefreshRates[i]->getFps().getIntValue() + << " Actual fps " << refreshRates[i].modePtr->getFps().getIntValue(); } } TEST_F(RefreshRateConfigsTest, touchConsidered) { - RefreshRateConfigs configs(kModes_60_90, kModeId60); + TestableRefreshRateConfigs configs(kModes_60_90, kModeId60); auto [_, signals] = configs.getRankedRefreshRates({}, {}); EXPECT_FALSE(signals.touch); - std::tie(std::ignore, signals) = configs.getRankedRefreshRates({}, {.touch = true}); + std::tie(std::ignore, signals) = configs.getRankedRefreshRatesAsPair({}, {.touch = true}); EXPECT_TRUE(signals.touch); std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}}; @@ -1206,7 +1218,7 @@ TEST_F(RefreshRateConfigsTest, touchConsidered) { lr2.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 60_Hz; lr2.name = "60Hz Heuristic"; - std::tie(std::ignore, signals) = configs.getRankedRefreshRates(layers, {.touch = true}); + std::tie(std::ignore, signals) = configs.getRankedRefreshRatesAsPair(layers, {.touch = true}); EXPECT_TRUE(signals.touch); lr1.vote = LayerVoteType::ExplicitDefault; @@ -1215,7 +1227,7 @@ TEST_F(RefreshRateConfigsTest, touchConsidered) { lr2.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 60_Hz; lr2.name = "60Hz Heuristic"; - std::tie(std::ignore, signals) = configs.getRankedRefreshRates(layers, {.touch = true}); + std::tie(std::ignore, signals) = configs.getRankedRefreshRatesAsPair(layers, {.touch = true}); EXPECT_FALSE(signals.touch); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -1224,7 +1236,7 @@ TEST_F(RefreshRateConfigsTest, touchConsidered) { lr2.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 60_Hz; lr2.name = "60Hz Heuristic"; - std::tie(std::ignore, signals) = configs.getRankedRefreshRates(layers, {.touch = true}); + std::tie(std::ignore, signals) = configs.getRankedRefreshRatesAsPair(layers, {.touch = true}); EXPECT_TRUE(signals.touch); lr1.vote = LayerVoteType::ExplicitDefault; @@ -1233,7 +1245,7 @@ TEST_F(RefreshRateConfigsTest, touchConsidered) { lr2.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 60_Hz; lr2.name = "60Hz Heuristic"; - std::tie(std::ignore, signals) = configs.getRankedRefreshRates(layers, {.touch = true}); + std::tie(std::ignore, signals) = configs.getRankedRefreshRatesAsPair(layers, {.touch = true}); EXPECT_FALSE(signals.touch); } @@ -1352,7 +1364,7 @@ TEST_F(RefreshRateConfigsTest, const auto [mode, signals] = configs.getRankedRefreshRates(layers, {.touch = true, .idle = true}); - EXPECT_EQ(mode.begin()->displayModePtr, kMode60); + EXPECT_EQ(mode.begin()->modePtr, kMode60); EXPECT_FALSE(signals.touch); } @@ -1407,18 +1419,15 @@ TEST_F(RefreshRateConfigsTest, testDisplayModeOrdering) { lr5.name = "30Hz"; lr5.focused = true; - std::vector<RefreshRateRanking> expectedRankings = { - RefreshRateRanking{kMode120}, RefreshRateRanking{kMode90}, RefreshRateRanking{kMode72}, - RefreshRateRanking{kMode60}, RefreshRateRanking{kMode30}, - }; + std::array expectedRanking = {kMode120, kMode90, kMode72, kMode60, kMode30}; + auto actualRanking = configs.getRankedRefreshRates(layers, {}).ranking; - std::vector<RefreshRateRanking> actualOrder = - configs.getRankedRefreshRatesAndSignals(layers, {}).first; - ASSERT_EQ(expectedRankings.size(), actualOrder.size()); - for (size_t i = 0; i < expectedRankings.size(); ++i) { - EXPECT_EQ(expectedRankings[i].displayModePtr, actualOrder[i].displayModePtr) - << "Expected fps " << expectedRankings[i].displayModePtr->getFps().getIntValue() - << " Actual fps " << actualOrder[i].displayModePtr->getFps().getIntValue(); + ASSERT_EQ(expectedRanking.size(), actualRanking.size()); + + for (size_t i = 0; i < expectedRanking.size(); ++i) { + EXPECT_EQ(expectedRanking[i], actualRanking[i].modePtr) + << "Expected fps " << expectedRanking[i]->getFps().getIntValue() << " Actual fps " + << actualRanking[i].modePtr->getFps().getIntValue(); } lr1.vote = LayerVoteType::Max; @@ -1436,18 +1445,15 @@ TEST_F(RefreshRateConfigsTest, testDisplayModeOrdering) { lr5.desiredRefreshRate = 120_Hz; lr5.name = "120Hz"; - expectedRankings = { - RefreshRateRanking{kMode120}, RefreshRateRanking{kMode90}, RefreshRateRanking{kMode72}, - RefreshRateRanking{kMode60}, RefreshRateRanking{kMode30}, - }; + expectedRanking = {kMode120, kMode90, kMode72, kMode60, kMode30}; + actualRanking = configs.getRankedRefreshRates(layers, {}).ranking; - actualOrder = configs.getRankedRefreshRatesAndSignals(layers, {}).first; + ASSERT_EQ(expectedRanking.size(), actualRanking.size()); - ASSERT_EQ(expectedRankings.size(), actualOrder.size()); - for (size_t i = 0; i < expectedRankings.size(); ++i) { - EXPECT_EQ(expectedRankings[i].displayModePtr, actualOrder[i].displayModePtr) - << "Expected fps " << expectedRankings[i].displayModePtr->getFps().getIntValue() - << " Actual fps " << actualOrder[i].displayModePtr->getFps().getIntValue(); + for (size_t i = 0; i < expectedRanking.size(); ++i) { + EXPECT_EQ(expectedRanking[i], actualRanking[i].modePtr) + << "Expected fps " << expectedRanking[i]->getFps().getIntValue() << " Actual fps " + << actualRanking[i].modePtr->getFps().getIntValue(); } lr1.vote = LayerVoteType::Heuristic; @@ -1463,17 +1469,15 @@ TEST_F(RefreshRateConfigsTest, testDisplayModeOrdering) { lr5.desiredRefreshRate = 72_Hz; lr5.name = "72Hz"; - expectedRankings = { - RefreshRateRanking{kMode30}, RefreshRateRanking{kMode60}, RefreshRateRanking{kMode90}, - RefreshRateRanking{kMode120}, RefreshRateRanking{kMode72}, - }; + expectedRanking = {kMode30, kMode60, kMode90, kMode120, kMode72}; + actualRanking = configs.getRankedRefreshRates(layers, {}).ranking; + + ASSERT_EQ(expectedRanking.size(), actualRanking.size()); - actualOrder = configs.getRankedRefreshRatesAndSignals(layers, {}).first; - ASSERT_EQ(expectedRankings.size(), actualOrder.size()); - for (size_t i = 0; i < expectedRankings.size(); ++i) { - EXPECT_EQ(expectedRankings[i].displayModePtr, actualOrder[i].displayModePtr) - << "Expected fps " << expectedRankings[i].displayModePtr->getFps().getIntValue() - << " Actual fps " << actualOrder[i].displayModePtr->getFps().getIntValue(); + for (size_t i = 0; i < expectedRanking.size(); ++i) { + EXPECT_EQ(expectedRanking[i], actualRanking[i].modePtr) + << "Expected fps " << expectedRanking[i]->getFps().getIntValue() << " Actual fps " + << actualRanking[i].modePtr->getFps().getIntValue(); } lr1.desiredRefreshRate = 120_Hz; @@ -1492,17 +1496,15 @@ TEST_F(RefreshRateConfigsTest, testDisplayModeOrdering) { lr5.desiredRefreshRate = 120_Hz; lr5.name = "120Hz-2"; - expectedRankings = { - RefreshRateRanking{kMode90}, RefreshRateRanking{kMode60}, RefreshRateRanking{kMode120}, - RefreshRateRanking{kMode72}, RefreshRateRanking{kMode30}, - }; + expectedRanking = {kMode90, kMode60, kMode120, kMode72, kMode30}; + actualRanking = configs.getRankedRefreshRates(layers, {}).ranking; + + ASSERT_EQ(expectedRanking.size(), actualRanking.size()); - actualOrder = configs.getRankedRefreshRatesAndSignals(layers, {}).first; - ASSERT_EQ(expectedRankings.size(), actualOrder.size()); - for (size_t i = 0; i < expectedRankings.size(); ++i) { - EXPECT_EQ(expectedRankings[i].displayModePtr, actualOrder[i].displayModePtr) - << "Expected fps " << expectedRankings[i].displayModePtr->getFps().getIntValue() - << " Actual fps " << actualOrder[i].displayModePtr->getFps().getIntValue(); + for (size_t i = 0; i < expectedRanking.size(); ++i) { + EXPECT_EQ(expectedRanking[i], actualRanking[i].modePtr) + << "Expected fps " << expectedRanking[i]->getFps().getIntValue() << " Actual fps " + << actualRanking[i].modePtr->getFps().getIntValue(); } } @@ -1513,8 +1515,8 @@ TEST_F(RefreshRateConfigsTest, EXPECT_EQ(SetPolicyResult::Changed, configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}, {60_Hz, 90_Hz}})); - const auto [mode, signals] = configs.getRankedRefreshRatesAndSignals({}, {}); - EXPECT_EQ(mode.front().displayModePtr, kMode90); + const auto [ranking, signals] = configs.getRankedRefreshRates({}, {}); + EXPECT_EQ(ranking.front().modePtr, kMode90); EXPECT_FALSE(signals.touch); std::vector<LayerRequirement> layers = {{.weight = 1.f}}; @@ -1892,13 +1894,12 @@ TEST_F(RefreshRateConfigsTest, idle) { layers[0].vote = voteType; layers[0].desiredRefreshRate = 90_Hz; - const auto [refreshRate, signals] = - configs.getRankedRefreshRatesAndSignals(layers, - {.touch = touchActive, .idle = true}); + const auto [ranking, signals] = + configs.getRankedRefreshRates(layers, {.touch = touchActive, .idle = true}); // Refresh rate will be chosen by either touch state or idle state. EXPECT_EQ(!touchActive, signals.idle); - return refreshRate.front().displayModePtr->getId(); + return ranking.front().modePtr->getId(); }; EXPECT_EQ(SetPolicyResult::Changed, @@ -2059,12 +2060,13 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ReadsCache) { const auto args = std::make_pair(std::vector<LayerRequirement>{}, GlobalSignals{.touch = true, .idle = true}); - const auto result = std::make_pair(std::vector<RefreshRateRanking>{RefreshRateRanking{kMode90}}, - GlobalSignals{.touch = true}); + const RefreshRateConfigs::RankedRefreshRates result = {{RefreshRateConfigs::ScoredRefreshRate{ + kMode90}}, + {.touch = true}}; configs.mutableGetRankedRefreshRatesCache() = {args, result}; - EXPECT_EQ(result, configs.getRankedRefreshRatesAndSignals(args.first, args.second)); + EXPECT_EQ(result, configs.getRankedRefreshRates(args.first, args.second)); } TEST_F(RefreshRateConfigsTest, getBestRefreshRate_WritesCache) { @@ -2075,7 +2077,7 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_WritesCache) { std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 0.5f}}; RefreshRateConfigs::GlobalSignals globalSignals{.touch = true, .idle = true}; - const auto result = configs.getRankedRefreshRatesAndSignals(layers, globalSignals); + const auto result = configs.getRankedRefreshRates(layers, globalSignals); const auto& cache = configs.mutableGetRankedRefreshRatesCache(); ASSERT_TRUE(cache); diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index 392398dbe3..147433b422 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -43,8 +43,6 @@ using MockEventThread = android::mock::EventThread; using MockLayer = android::mock::MockLayer; using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector; -constexpr PhysicalDisplayId PHYSICAL_DISPLAY_ID = PhysicalDisplayId::fromPort(255u); - class SchedulerTest : public testing::Test { protected: class MockEventThreadConnection : public android::EventThreadConnection { @@ -61,14 +59,28 @@ protected: SchedulerTest(); - static inline const DisplayModePtr kMode60_1 = createDisplayMode(DisplayModeId(0), 60_Hz); - static inline const DisplayModePtr kMode120_1 = createDisplayMode(DisplayModeId(1), 120_Hz); - static inline const DisplayModePtr kMode60_2 = createDisplayMode(DisplayModeId(2), 60_Hz); - static inline const DisplayModePtr kMode120_2 = createDisplayMode(DisplayModeId(3), 120_Hz); - static inline const DisplayModePtr kMode60_3 = createDisplayMode(DisplayModeId(4), 60_Hz); + static constexpr PhysicalDisplayId kDisplayId1 = PhysicalDisplayId::fromPort(255u); + static inline const DisplayModePtr kDisplay1Mode60 = + createDisplayMode(kDisplayId1, DisplayModeId(0), 60_Hz); + static inline const DisplayModePtr kDisplay1Mode120 = + createDisplayMode(kDisplayId1, DisplayModeId(1), 120_Hz); + static inline const DisplayModes kDisplay1Modes = makeModes(kDisplay1Mode60, kDisplay1Mode120); + + static constexpr PhysicalDisplayId kDisplayId2 = PhysicalDisplayId::fromPort(254u); + static inline const DisplayModePtr kDisplay2Mode60 = + createDisplayMode(kDisplayId2, DisplayModeId(0), 60_Hz); + static inline const DisplayModePtr kDisplay2Mode120 = + createDisplayMode(kDisplayId2, DisplayModeId(1), 120_Hz); + static inline const DisplayModes kDisplay2Modes = makeModes(kDisplay2Mode60, kDisplay2Mode120); + + static constexpr PhysicalDisplayId kDisplayId3 = PhysicalDisplayId::fromPort(253u); + static inline const DisplayModePtr kDisplay3Mode60 = + createDisplayMode(kDisplayId3, DisplayModeId(0), 60_Hz); + static inline const DisplayModes kDisplay3Modes = makeModes(kDisplay3Mode60); std::shared_ptr<RefreshRateConfigs> mConfigs = - std::make_shared<RefreshRateConfigs>(makeModes(kMode60_1), kMode60_1->getId()); + std::make_shared<RefreshRateConfigs>(makeModes(kDisplay1Mode60), + kDisplay1Mode60->getId()); mock::SchedulerCallback mSchedulerCallback; TestableScheduler* mScheduler = new TestableScheduler{mConfigs, mSchedulerCallback}; @@ -114,7 +126,7 @@ TEST_F(SchedulerTest, invalidConnectionHandle) { // The EXPECT_CALLS make sure we don't call the functions on the subsequent event threads. EXPECT_CALL(*mEventThread, onHotplugReceived(_, _)).Times(0); - mScheduler->onHotplugReceived(handle, PHYSICAL_DISPLAY_ID, false); + mScheduler->onHotplugReceived(handle, kDisplayId1, false); EXPECT_CALL(*mEventThread, onScreenAcquired()).Times(0); mScheduler->onScreenAcquired(handle); @@ -138,8 +150,8 @@ TEST_F(SchedulerTest, validConnectionHandle) { ASSERT_EQ(mEventThreadConnection, connection); EXPECT_TRUE(mScheduler->getEventConnection(mConnectionHandle)); - EXPECT_CALL(*mEventThread, onHotplugReceived(PHYSICAL_DISPLAY_ID, false)).Times(1); - mScheduler->onHotplugReceived(mConnectionHandle, PHYSICAL_DISPLAY_ID, false); + EXPECT_CALL(*mEventThread, onHotplugReceived(kDisplayId1, false)).Times(1); + mScheduler->onHotplugReceived(mConnectionHandle, kDisplayId1, false); EXPECT_CALL(*mEventThread, onScreenAcquired()).Times(1); mScheduler->onScreenAcquired(mConnectionHandle); @@ -185,8 +197,7 @@ TEST_F(SchedulerTest, updateDisplayModes) { ASSERT_EQ(1u, mScheduler->layerHistorySize()); mScheduler->setRefreshRateConfigs( - std::make_shared<RefreshRateConfigs>(makeModes(kMode60_1, kMode120_1), - kMode60_1->getId())); + std::make_shared<RefreshRateConfigs>(kDisplay1Modes, kDisplay1Mode60->getId())); ASSERT_EQ(0u, mScheduler->getNumActiveLayers()); mScheduler->recordLayerHistory(layer.get(), 0, LayerHistory::LayerUpdateType::Buffer); @@ -203,7 +214,7 @@ TEST_F(SchedulerTest, dispatchCachedReportedMode) { TEST_F(SchedulerTest, onNonPrimaryDisplayModeChanged_invalidParameters) { const auto mode = DisplayMode::Builder(hal::HWConfigId(0)) .setId(DisplayModeId(111)) - .setPhysicalDisplayId(PHYSICAL_DISPLAY_ID) + .setPhysicalDisplayId(kDisplayId1) .setVsyncPeriod(111111) .build(); @@ -225,14 +236,15 @@ TEST_F(SchedulerTest, calculateMaxAcquiredBufferCount) { } MATCHER(Is120Hz, "") { - return isApproxEqual(arg.front().displayModePtr->getFps(), 120_Hz); + return isApproxEqual(arg.front().modePtr->getFps(), 120_Hz); } TEST_F(SchedulerTest, chooseRefreshRateForContentSelectsMaxRefreshRate) { - auto display = - mFakeDisplayInjector.injectInternalDisplay([&](FakeDisplayDeviceInjector& injector) { - injector.setDisplayModes(makeModes(kMode60_1, kMode120_1), kMode60_1->getId()); - }); + const auto display = mFakeDisplayInjector.injectInternalDisplay( + [&](FakeDisplayDeviceInjector& injector) { + injector.setDisplayModes(kDisplay1Modes, kDisplay1Mode60->getId()); + }, + {.displayId = kDisplayId1}); mScheduler->registerDisplay(display); mScheduler->setRefreshRateConfigs(display->holdRefreshRateConfigs()); @@ -256,11 +268,12 @@ TEST_F(SchedulerTest, chooseRefreshRateForContentSelectsMaxRefreshRate) { mScheduler->chooseRefreshRateForContent(); } -TEST_F(SchedulerTest, getBestDisplayMode_singleDisplay) { - auto display = - mFakeDisplayInjector.injectInternalDisplay([&](FakeDisplayDeviceInjector& injector) { - injector.setDisplayModes(makeModes(kMode60_1, kMode120_1), kMode60_1->getId()); - }); +TEST_F(SchedulerTest, chooseDisplayModesSingleDisplay) { + const auto display = mFakeDisplayInjector.injectInternalDisplay( + [&](FakeDisplayDeviceInjector& injector) { + injector.setDisplayModes(kDisplay1Modes, kDisplay1Mode60->getId()); + }, + {.displayId = kDisplayId1}); mScheduler->registerDisplay(display); @@ -270,115 +283,125 @@ TEST_F(SchedulerTest, getBestDisplayMode_singleDisplay) { GlobalSignals globalSignals = {.idle = true}; mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals); - std::vector<DisplayModeConfig> displayModeConfigs = mScheduler->getBestDisplayModeConfigs(); - ASSERT_EQ(1ul, displayModeConfigs.size()); - EXPECT_EQ(displayModeConfigs.front().displayModePtr, kMode60_1); - EXPECT_EQ(displayModeConfigs.front().signals, globalSignals); + using DisplayModeChoice = TestableScheduler::DisplayModeChoice; + + auto modeChoices = mScheduler->chooseDisplayModes(); + ASSERT_EQ(1u, modeChoices.size()); + + auto choice = modeChoices.get(kDisplayId1); + ASSERT_TRUE(choice); + EXPECT_EQ(choice->get(), DisplayModeChoice(kDisplay1Mode60, globalSignals)); globalSignals = {.idle = false}; mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals); - displayModeConfigs = mScheduler->getBestDisplayModeConfigs(); - ASSERT_EQ(1ul, displayModeConfigs.size()); - EXPECT_EQ(displayModeConfigs.front().displayModePtr, kMode120_1); - EXPECT_EQ(displayModeConfigs.front().signals, globalSignals); + + modeChoices = mScheduler->chooseDisplayModes(); + ASSERT_EQ(1u, modeChoices.size()); + + choice = modeChoices.get(kDisplayId1); + ASSERT_TRUE(choice); + EXPECT_EQ(choice->get(), DisplayModeChoice(kDisplay1Mode120, globalSignals)); globalSignals = {.touch = true}; mScheduler->replaceTouchTimer(10); mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals); - displayModeConfigs = mScheduler->getBestDisplayModeConfigs(); - ASSERT_EQ(1ul, displayModeConfigs.size()); - EXPECT_EQ(displayModeConfigs.front().displayModePtr, kMode120_1); - EXPECT_EQ(displayModeConfigs.front().signals, globalSignals); - mScheduler->unregisterDisplay(display->getPhysicalId()); + modeChoices = mScheduler->chooseDisplayModes(); + ASSERT_EQ(1u, modeChoices.size()); + + choice = modeChoices.get(kDisplayId1); + ASSERT_TRUE(choice); + EXPECT_EQ(choice->get(), DisplayModeChoice(kDisplay1Mode120, globalSignals)); + + mScheduler->unregisterDisplay(kDisplayId1); EXPECT_TRUE(mScheduler->mutableDisplays().empty()); } -TEST_F(SchedulerTest, getBestDisplayModes_multipleDisplays) { - auto display1 = - mFakeDisplayInjector.injectInternalDisplay([&](FakeDisplayDeviceInjector& injector) { - injector.setDisplayModes(makeModes(kMode60_1, kMode120_1), kMode60_1->getId()); - }); - auto display2 = mFakeDisplayInjector.injectInternalDisplay( +TEST_F(SchedulerTest, chooseDisplayModesMultipleDisplays) { + const auto display1 = mFakeDisplayInjector.injectInternalDisplay( + [&](FakeDisplayDeviceInjector& injector) { + injector.setDisplayModes(kDisplay1Modes, kDisplay1Mode60->getId()); + }, + {.displayId = kDisplayId1, .hwcDisplayId = 42, .isPrimary = true}); + const auto display2 = mFakeDisplayInjector.injectInternalDisplay( [&](FakeDisplayDeviceInjector& injector) { - injector.setDisplayModes(makeModes(kMode60_2, kMode120_2), kMode60_2->getId()); + injector.setDisplayModes(kDisplay2Modes, kDisplay2Mode60->getId()); }, - {.port = 253u, .hwcDisplayId = 42, .isPrimary = false}); + {.displayId = kDisplayId2, .hwcDisplayId = 41, .isPrimary = false}); mScheduler->registerDisplay(display1); mScheduler->registerDisplay(display2); - std::vector<sp<DisplayDevice>> expectedDisplays = {display1, display2}; - std::vector<RefreshRateConfigs::LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}}; - GlobalSignals globalSignals = {.idle = true}; - std::vector<DisplayModeConfig> expectedConfigs = {DisplayModeConfig{globalSignals, kMode60_1}, - DisplayModeConfig{globalSignals, kMode60_2}}; + using DisplayModeChoice = TestableScheduler::DisplayModeChoice; + TestableScheduler::DisplayModeChoiceMap expectedChoices; - mScheduler->setContentRequirements(layers); - mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals); - std::vector<DisplayModeConfig> displayModeConfigs = mScheduler->getBestDisplayModeConfigs(); - ASSERT_EQ(displayModeConfigs.size(), expectedConfigs.size()); - for (size_t i = 0; i < expectedConfigs.size(); ++i) { - EXPECT_EQ(expectedConfigs.at(i).displayModePtr, displayModeConfigs.at(i).displayModePtr) - << "Expected fps " << expectedConfigs.at(i).displayModePtr->getFps().getIntValue() - << " Actual fps " - << displayModeConfigs.at(i).displayModePtr->getFps().getIntValue(); - EXPECT_EQ(globalSignals, displayModeConfigs.at(i).signals); - } + { + const GlobalSignals globalSignals = {.idle = true}; + expectedChoices = + ftl::init::map<const PhysicalDisplayId&, + DisplayModeChoice>(kDisplayId1, kDisplay1Mode60, + globalSignals)(kDisplayId2, kDisplay2Mode60, + globalSignals); - expectedConfigs = std::vector<DisplayModeConfig>{DisplayModeConfig{globalSignals, kMode120_1}, - DisplayModeConfig{globalSignals, kMode120_2}}; + std::vector<RefreshRateConfigs::LayerRequirement> layers = {{.weight = 1.f}, + {.weight = 1.f}}; + mScheduler->setContentRequirements(layers); + mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals); - globalSignals = {.idle = false}; - mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals); - displayModeConfigs = mScheduler->getBestDisplayModeConfigs(); - ASSERT_EQ(expectedConfigs.size(), displayModeConfigs.size()); - for (size_t i = 0; i < expectedConfigs.size(); ++i) { - EXPECT_EQ(expectedConfigs.at(i).displayModePtr, displayModeConfigs.at(i).displayModePtr) - << "Expected fps " << expectedConfigs.at(i).displayModePtr->getFps().getIntValue() - << " Actual fps " - << displayModeConfigs.at(i).displayModePtr->getFps().getIntValue(); - EXPECT_EQ(globalSignals, displayModeConfigs.at(i).signals); + const auto actualChoices = mScheduler->chooseDisplayModes(); + EXPECT_EQ(expectedChoices, actualChoices); } - - globalSignals = {.touch = true}; - mScheduler->replaceTouchTimer(10); - mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals); - displayModeConfigs = mScheduler->getBestDisplayModeConfigs(); - ASSERT_EQ(expectedConfigs.size(), displayModeConfigs.size()); - for (size_t i = 0; i < expectedConfigs.size(); ++i) { - EXPECT_EQ(expectedConfigs.at(i).displayModePtr, displayModeConfigs.at(i).displayModePtr) - << "Expected fps " << expectedConfigs.at(i).displayModePtr->getFps().getIntValue() - << " Actual fps " - << displayModeConfigs.at(i).displayModePtr->getFps().getIntValue(); - EXPECT_EQ(globalSignals, displayModeConfigs.at(i).signals); + { + const GlobalSignals globalSignals = {.idle = false}; + expectedChoices = + ftl::init::map<const PhysicalDisplayId&, + DisplayModeChoice>(kDisplayId1, kDisplay1Mode120, + globalSignals)(kDisplayId2, kDisplay2Mode120, + globalSignals); + + mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals); + + const auto actualChoices = mScheduler->chooseDisplayModes(); + EXPECT_EQ(expectedChoices, actualChoices); } - - // Filters out the 120Hz as it's not present on the display3, even with touch active - // we select 60Hz here. - auto display3 = mFakeDisplayInjector.injectInternalDisplay( - [&](FakeDisplayDeviceInjector& injector) { - injector.setDisplayModes(makeModes(kMode60_3), kMode60_3->getId()); - }, - {.port = 252u, .hwcDisplayId = 41, .isPrimary = false}); - - mScheduler->registerDisplay(display3); - - expectedDisplays = {display1, display2, display3}; - globalSignals = {.touch = true}; - mScheduler->replaceTouchTimer(10); - expectedConfigs = std::vector<DisplayModeConfig>{DisplayModeConfig{globalSignals, kMode60_1}, - DisplayModeConfig{globalSignals, kMode60_2}, - DisplayModeConfig{globalSignals, kMode60_3}}; - mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals); - displayModeConfigs = mScheduler->getBestDisplayModeConfigs(); - ASSERT_EQ(expectedConfigs.size(), displayModeConfigs.size()); - for (size_t i = 0; i < expectedConfigs.size(); ++i) { - EXPECT_EQ(expectedConfigs.at(i).displayModePtr, displayModeConfigs.at(i).displayModePtr) - << "Expected fps " << expectedConfigs.at(i).displayModePtr->getFps().getIntValue() - << " Actual fps " - << displayModeConfigs.at(i).displayModePtr->getFps().getIntValue(); - EXPECT_EQ(globalSignals, displayModeConfigs.at(i).signals); + { + const GlobalSignals globalSignals = {.touch = true}; + mScheduler->replaceTouchTimer(10); + mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals); + + expectedChoices = + ftl::init::map<const PhysicalDisplayId&, + DisplayModeChoice>(kDisplayId1, kDisplay1Mode120, + globalSignals)(kDisplayId2, kDisplay2Mode120, + globalSignals); + + const auto actualChoices = mScheduler->chooseDisplayModes(); + EXPECT_EQ(expectedChoices, actualChoices); + } + { + // This display does not support 120 Hz, so we should choose 60 Hz despite the touch signal. + const auto display3 = mFakeDisplayInjector.injectInternalDisplay( + [&](FakeDisplayDeviceInjector& injector) { + injector.setDisplayModes(kDisplay3Modes, kDisplay3Mode60->getId()); + }, + {.displayId = kDisplayId3, .hwcDisplayId = 40, .isPrimary = false}); + + mScheduler->registerDisplay(display3); + + const GlobalSignals globalSignals = {.touch = true}; + mScheduler->replaceTouchTimer(10); + mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals); + + expectedChoices = + ftl::init::map<const PhysicalDisplayId&, + DisplayModeChoice>(kDisplayId1, kDisplay1Mode60, + globalSignals)(kDisplayId2, kDisplay2Mode60, + globalSignals)(kDisplayId3, + kDisplay3Mode60, + globalSignals); + + const auto actualChoices = mScheduler->chooseDisplayModes(); + EXPECT_EQ(expectedChoices, actualChoices); } } diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index 68df987689..26b2b673a2 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -107,9 +107,12 @@ public: mPolicy.contentRequirements = std::move(layers); } - std::vector<DisplayModeConfig> getBestDisplayModeConfigs() { + using Scheduler::DisplayModeChoice; + using Scheduler::DisplayModeChoiceMap; + + DisplayModeChoiceMap chooseDisplayModes() { std::lock_guard<std::mutex> lock(mPolicyLock); - return Scheduler::getBestDisplayModeConfigs(); + return Scheduler::chooseDisplayModes(); } void dispatchCachedReportedMode() { diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplayMode.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplayMode.h index a83ecbca26..c78b6bdc18 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplayMode.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplayMode.h @@ -33,4 +33,9 @@ inline DisplayModePtr createDisplayMode( .build(); } +inline DisplayModePtr createDisplayMode(PhysicalDisplayId displayId, DisplayModeId modeId, + Fps refreshRate) { + return createDisplayMode(modeId, refreshRate, {}, {}, displayId); +} + } // namespace android::mock diff --git a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h index 8af2dfa9cf..7d4b159e5e 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h +++ b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h @@ -24,14 +24,14 @@ namespace android::scheduler::mock { struct SchedulerCallback final : ISchedulerCallback { MOCK_METHOD(void, setVsyncEnabled, (bool), (override)); - MOCK_METHOD(void, requestDisplayModes, (std::vector<scheduler::DisplayModeConfig>), (override)); + MOCK_METHOD(void, requestDisplayModes, (std::vector<display::DisplayModeRequest>), (override)); MOCK_METHOD(void, kernelTimerChanged, (bool), (override)); MOCK_METHOD(void, triggerOnFrameRateOverridesChanged, (), (override)); }; struct NoOpSchedulerCallback final : ISchedulerCallback { void setVsyncEnabled(bool) override {} - void requestDisplayModes(std::vector<scheduler::DisplayModeConfig>) override {} + void requestDisplayModes(std::vector<display::DisplayModeRequest>) override {} void kernelTimerChanged(bool) override {} void triggerOnFrameRateOverridesChanged() override {} }; |