SF: Clean up API for refresh rate selection
Define types for each step: ScoredRefreshRate, RefreshRateRanking,
RankedRefreshRates, DisplayModeChoice, and DisplayModeRequest. The
last will replace DisplayDevice::ActiveModeInfo in a follow-up CL.
Add Scheduler::mLeaderDisplayId (always the primary display for now)
and provisionally use its DisplayModeChoice until Scheduler::Policy
is tracked per display.
Rewrite multi-display tests, which relied on each DisplayMode having
the same PhysicalDisplayId, and did not actually verify mode/display
association (`expectedDisplays` was unused). Test RefreshRateRanking
ordering by descending score.
Bug: 241285191
Test: libsurfaceflinger_unittest
Change-Id: I1d24d6a1fa9285aa7fc4bf2dd6654fa660d27b08
diff --git a/libs/ui/include/ui/DisplayId.h b/libs/ui/include/ui/DisplayId.h
index d0c03fe..3a31fa0 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 @@
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 0000000..ac25fe0
--- /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 06a812b..7abb94b 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 @@
/* ------------------------------------------------------------------------
* 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 30483a2..39850c7 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 @@
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 @@
}
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::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 @@
// 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 @@
// 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 @@
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 @@
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 @@
// 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 @@
}
}();
- 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 @@
// 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 @@
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 @@
}
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 7219584..99f81aa 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 @@
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 @@
return touch == other.touch && idle == other.idle &&
powerOnImminent == other.powerOnImminent;
}
+
+ auto toString() const {
+ return ftl::Concat("{touch=", touch, ", idle=", idle,
+ ", powerOnImminent=", powerOnImminent, '}');
+ }
};
- // 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);
+ 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;
+ }
+ };
+
+ RankedRefreshRates getRankedRefreshRates(const std::vector<LayerRequirement>&,
+ GlobalSignals) const EXCLUDES(mLock);
FpsRange getSupportedRefreshRateRange() const EXCLUDES(mLock) {
std::lock_guard lock(mLock);
@@ -354,8 +380,8 @@
// 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 @@
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 @@
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 30f2c27..be3ebb7 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -127,11 +127,19 @@
}
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 @@
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 @@
if (currentState == newState) return {};
currentState = std::forward<T>(newState);
- displayModeConfigs = getBestDisplayModeConfigs();
+ auto modeChoices = chooseDisplayModes();
- // 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();
+ // 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();
- newMode = displayModeConfigForCurrentPolicy.displayModePtr;
- consideredSignals = displayModeConfigForCurrentPolicy.signals;
- frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps());
+ 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});
+ }
- if (mPolicy.mode == newMode) {
+ 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 @@
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 @@
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 @@
}
}
- perDisplayRankings.emplace_back(std::move(rankings), signals);
+ perDisplayRanking.push_back(std::move(rankedRefreshRates));
}
auto maxScoreIt = refreshRateTallies.cbegin();
@@ -750,26 +756,27 @@
? 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 @@
// 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 6633b05..33f6126 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 @@
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 @@
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 @@
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 029dd9f..8e29715 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1064,30 +1064,28 @@
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 @@
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 @@
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() {
@@ -6583,18 +6580,19 @@
}
}
-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(
@@ -6650,7 +6648,7 @@
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 b65dec4..9ffe6ab 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 @@
mCounterByLayerHandle GUARDED_BY(mLock);
};
- using ActiveModeInfo = DisplayDevice::ActiveModeInfo;
- using KernelIdleTimerController =
- ::android::scheduler::RefreshRateConfigs::KernelIdleTimerController;
-
enum class BootStage {
BOOTLOADER,
BOOTANIMATION,
@@ -628,16 +625,17 @@
// 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 @@
// 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 @@
// 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 e2ae4f4..99279dc 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -780,7 +780,7 @@
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 6ee4b9b..6e4bf2b 100644
--- a/services/surfaceflinger/tests/unittests/FakeDisplayInjector.h
+++ b/services/surfaceflinger/tests/unittests/FakeDisplayInjector.h
@@ -29,7 +29,7 @@
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 @@
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 620825f..924c5be 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 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 @@
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 @@
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 @@
class RefreshRateConfigsTest : public testing::Test {
protected:
+ using RefreshRateOrder = TestableRefreshRateConfigs::RefreshRateOrder;
+
RefreshRateConfigsTest();
~RefreshRateConfigsTest();
@@ -1050,20 +1066,17 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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;
- 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.desiredRefreshRate = 120_Hz;
@@ -1492,17 +1496,15 @@
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;
- 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();
}
}
@@ -1513,8 +1515,8 @@
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 @@
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 @@
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 @@
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 392398d..147433b 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -43,8 +43,6 @@
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 @@
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 @@
// 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 @@
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 @@
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, 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 @@
}
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 @@
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 @@
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(makeModes(kMode60_2, kMode120_2), kMode60_2->getId());
+ injector.setDisplayModes(kDisplay1Modes, kDisplay1Mode60->getId());
},
- {.port = 253u, .hwcDisplayId = 42, .isPrimary = false});
+ {.displayId = kDisplayId1, .hwcDisplayId = 42, .isPrimary = true});
+ const auto display2 = mFakeDisplayInjector.injectInternalDisplay(
+ [&](FakeDisplayDeviceInjector& injector) {
+ injector.setDisplayModes(kDisplay2Modes, kDisplay2Mode60->getId());
+ },
+ {.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);
+
+ std::vector<RefreshRateConfigs::LayerRequirement> layers = {{.weight = 1.f},
+ {.weight = 1.f}};
+ mScheduler->setContentRequirements(layers);
+ mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals);
+
+ const auto actualChoices = mScheduler->chooseDisplayModes();
+ EXPECT_EQ(expectedChoices, actualChoices);
}
+ {
+ const GlobalSignals globalSignals = {.idle = false};
+ expectedChoices =
+ ftl::init::map<const PhysicalDisplayId&,
+ DisplayModeChoice>(kDisplayId1, kDisplay1Mode120,
+ globalSignals)(kDisplayId2, kDisplay2Mode120,
+ globalSignals);
- expectedConfigs = std::vector<DisplayModeConfig>{DisplayModeConfig{globalSignals, kMode120_1},
- DisplayModeConfig{globalSignals, kMode120_2}};
+ 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);
}
+ {
+ const GlobalSignals globalSignals = {.touch = true};
+ mScheduler->replaceTouchTimer(10);
+ mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals);
- 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);
+ 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});
- // 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);
- mScheduler->registerDisplay(display3);
+ const GlobalSignals globalSignals = {.touch = true};
+ mScheduler->replaceTouchTimer(10);
+ mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals);
- 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);
+ 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 68df987..26b2b67 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -107,9 +107,12 @@
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 a83ecbc..c78b6bd 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplayMode.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplayMode.h
@@ -33,4 +33,9 @@
.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 8af2dfa..7d4b159 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
@@ -24,14 +24,14 @@
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 {}
};