SF: Generalize frame rate override to any frame rate
Add support to be able to override the frame rate of an app to
any frame rate, as long as it is a divisor of the display refresh rate.
Test: SF unit tests
Bug: 241460058
Bug: 241447632
Change-Id: Ibf8fa600127d3d5672a4c2a58d0a93b190854cc1
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
index f22f9e7..c913891 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
@@ -30,6 +30,7 @@
#include <ftl/enum.h>
#include <ftl/fake_guard.h>
#include <ftl/match.h>
+#include <ftl/unit.h>
#include <utils/Trace.h>
#include "../SurfaceFlingerProperties.h"
@@ -105,7 +106,7 @@
return sortedModes;
}
-bool canModesSupportFrameRateOverride(const std::vector<DisplayModeIterator>& sortedModes) {
+bool shouldEnableFrameRateOverride(const std::vector<DisplayModeIterator>& sortedModes) {
for (const auto it1 : sortedModes) {
const auto& mode1 = it1->second;
for (const auto it2 : sortedModes) {
@@ -264,7 +265,7 @@
if (layer.vote == LayerVoteType::ExplicitExact) {
const int divisor = getFrameRateDivisor(refreshRate, layer.desiredRefreshRate);
- if (mSupportsFrameRateOverrideByContent) {
+ if (supportsFrameRateOverrideByContent()) {
// Since we support frame rate override, allow refresh rates which are
// multiples of the layer's request, as those apps would be throttled
// down to run at the desired refresh rate.
@@ -579,7 +580,7 @@
// vote we should not change it if we get a touch event. Only apply touch boost if it will
// actually increase the refresh rate over the normal selection.
const bool touchBoostForExplicitExact = [&] {
- if (mSupportsFrameRateOverrideByContent) {
+ if (supportsFrameRateOverrideByContent()) {
// Enable touch boost if there are other layers besides exact
return explicitExact + noVoteLayers != layers.size();
} else {
@@ -648,23 +649,43 @@
GlobalSignals globalSignals) const
-> UidToFrameRateOverride {
ATRACE_CALL();
-
ALOGV("%s: %zu layers", __func__, layers.size());
std::lock_guard lock(mLock);
- std::vector<RefreshRateScore> scores;
- scores.reserve(mDisplayModes.size());
-
- for (auto it = mDisplayModes.begin(); it != mDisplayModes.end(); ++it) {
- scores.emplace_back(RefreshRateScore{it, 0.0f});
+ // Prepare a set of supported display refresh rates for easy lookup
+ constexpr size_t kStaticCapacity = 8;
+ ftl::SmallMap<Fps, ftl::Unit, kStaticCapacity, FpsApproxEqual> supportedDisplayRefreshRates;
+ if (mConfig.enableFrameRateOverride ==
+ Config::FrameRateOverride::EnabledForNativeRefreshRates) {
+ for (const auto& [_, modePtr] : mDisplayModes) {
+ supportedDisplayRefreshRates.try_emplace(modePtr->getFps(), ftl::unit);
+ }
}
- std::sort(scores.begin(), scores.end(), [](const auto& lhs, const auto& rhs) {
- const auto& mode1 = lhs.modeIt->second;
- const auto& mode2 = rhs.modeIt->second;
- return isStrictlyLess(mode1->getFps(), mode2->getFps());
- });
+ const auto* policyPtr = getCurrentPolicyLocked();
+ // We don't want to run lower than 30fps
+ const Fps minFrameRate = std::max(policyPtr->appRequestRanges.render.min, 30_Hz, isApproxLess);
+
+ using fps_approx_ops::operator/;
+ const unsigned numMultiples = displayRefreshRate / minFrameRate;
+
+ std::vector<std::pair<Fps, float>> scoredFrameRates;
+ scoredFrameRates.reserve(numMultiples);
+
+ for (unsigned n = numMultiples; n > 0; n--) {
+ const Fps divisor = displayRefreshRate / n;
+ if (mConfig.enableFrameRateOverride ==
+ Config::FrameRateOverride::EnabledForNativeRefreshRates &&
+ !supportedDisplayRefreshRates.contains(divisor)) {
+ continue;
+ }
+
+ if (policyPtr->appRequestRanges.render.includes(divisor)) {
+ ALOGV("%s: adding %s as a potential frame rate", __func__, to_string(divisor).c_str());
+ scoredFrameRates.emplace_back(divisor, 0);
+ }
+ }
const auto layersByUid = groupLayersByUid(layers);
UidToFrameRateOverride frameRateOverrides;
@@ -680,7 +701,7 @@
continue;
}
- for (auto& [_, score, _1] : scores) {
+ for (auto& [_, score] : scoredFrameRates) {
score = 0;
}
@@ -692,36 +713,33 @@
LOG_ALWAYS_FATAL_IF(layer->vote != LayerVoteType::ExplicitDefault &&
layer->vote != LayerVoteType::ExplicitExactOrMultiple &&
layer->vote != LayerVoteType::ExplicitExact);
- for (auto& [modeIt, score, _] : scores) {
+ for (auto& [fps, score] : scoredFrameRates) {
constexpr bool isSeamlessSwitch = true;
- const auto layerScore = calculateLayerScoreLocked(*layer, modeIt->second->getFps(),
- isSeamlessSwitch);
+ const auto layerScore = calculateLayerScoreLocked(*layer, fps, isSeamlessSwitch);
score += layer->weight * layerScore;
}
}
- // We just care about the refresh rates which are a divisor of the
- // display refresh rate
- const auto it = std::remove_if(scores.begin(), scores.end(), [&](RefreshRateScore score) {
- const auto& [id, mode] = *score.modeIt;
- return getFrameRateDivisor(displayRefreshRate, mode->getFps()) == 0;
- });
- scores.erase(it, scores.end());
-
// If we never scored any layers, we don't have a preferred frame rate
- if (std::all_of(scores.begin(), scores.end(),
- [](RefreshRateScore score) { return score.overallScore == 0; })) {
+ if (std::all_of(scoredFrameRates.begin(), scoredFrameRates.end(),
+ [](const auto& scoredFrameRate) {
+ const auto [_, score] = scoredFrameRate;
+ return score == 0;
+ })) {
continue;
}
// Now that we scored all the refresh rates we need to pick the lowest refresh rate
// that got the highest score.
- const DisplayModePtr& bestRefreshRate =
- std::min_element(scores.begin(), scores.end(),
- RefreshRateScoreComparator{.refreshRateOrder =
- RefreshRateOrder::Ascending})
- ->modeIt->second;
- frameRateOverrides.emplace(uid, bestRefreshRate->getFps());
+ const auto [overrideFps, _] =
+ *std::max_element(scoredFrameRates.begin(), scoredFrameRates.end(),
+ [](const auto& lhsPair, const auto& rhsPair) {
+ const float lhs = lhsPair.second;
+ const float rhs = rhsPair.second;
+ return lhs < rhs && !ScoredRefreshRate::scoresEqual(lhs, rhs);
+ });
+ ALOGV("%s: overriding to %s for uid=%d", __func__, to_string(overrideFps).c_str(), uid);
+ frameRateOverrides.emplace(uid, overrideFps);
}
return frameRateOverrides;
@@ -894,8 +912,17 @@
mDisplayManagerPolicy = {};
mDisplayManagerPolicy.defaultMode = activeModeId;
- mSupportsFrameRateOverrideByContent =
- mConfig.enableFrameRateOverride && canModesSupportFrameRateOverride(sortedModes);
+ mFrameRateOverrideConfig = [&] {
+ switch (mConfig.enableFrameRateOverride) {
+ case Config::FrameRateOverride::Disabled:
+ case Config::FrameRateOverride::Enabled:
+ return mConfig.enableFrameRateOverride;
+ case Config::FrameRateOverride::EnabledForNativeRefreshRates:
+ return shouldEnableFrameRateOverride(sortedModes)
+ ? Config::FrameRateOverride::EnabledForNativeRefreshRates
+ : Config::FrameRateOverride::Disabled;
+ }
+ }();
constructAvailableRefreshRates();
}
@@ -1128,7 +1155,7 @@
dumper.dump("overridePolicy"sv, currentPolicy.toString());
}
- dumper.dump("supportsFrameRateOverrideByContent"sv, mSupportsFrameRateOverrideByContent);
+ dumper.dump("frameRateOverrideConfig"sv, *ftl::enum_name(mFrameRateOverrideConfig));
std::string idleTimer;
if (mIdleTimer) {
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.h b/services/surfaceflinger/Scheduler/RefreshRateSelector.h
index 887d815..abbd304 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.h
@@ -251,7 +251,20 @@
// Configuration flags.
struct Config {
- bool enableFrameRateOverride = false;
+ enum class FrameRateOverride {
+ // Do not override the frame rate for an app
+ Disabled,
+
+ // Override the frame rate for an app to a value which is also
+ // a display refresh rate
+ EnabledForNativeRefreshRates,
+
+ // Override the frame rate for an app to any value
+ Enabled,
+
+ ftl_last = Enabled
+ };
+ FrameRateOverride enableFrameRateOverride = FrameRateOverride::Disabled;
// Specifies the upper refresh rate threshold (inclusive) for layer vote types of multiple
// or heuristic, such that refresh rates higher than this value will not be voted for. 0 if
@@ -266,11 +279,12 @@
std::optional<KernelIdleTimerController> kernelIdleTimerController;
};
- RefreshRateSelector(DisplayModes, DisplayModeId activeModeId,
- Config config = {.enableFrameRateOverride = false,
- .frameRateMultipleThreshold = 0,
- .idleTimerTimeout = 0ms,
- .kernelIdleTimerController = {}});
+ RefreshRateSelector(
+ DisplayModes, DisplayModeId activeModeId,
+ Config config = {.enableFrameRateOverride = Config::FrameRateOverride::Disabled,
+ .frameRateMultipleThreshold = 0,
+ .idleTimerTimeout = 0ms,
+ .kernelIdleTimerController = {}});
RefreshRateSelector(const RefreshRateSelector&) = delete;
RefreshRateSelector& operator=(const RefreshRateSelector&) = delete;
@@ -293,7 +307,9 @@
// refresh rates.
KernelIdleTimerAction getIdleTimerAction() const;
- bool supportsFrameRateOverrideByContent() const { return mSupportsFrameRateOverrideByContent; }
+ bool supportsFrameRateOverrideByContent() const {
+ return mFrameRateOverrideConfig != Config::FrameRateOverride::Disabled;
+ }
// Return the display refresh rate divisor to match the layer
// frame rate, or 0 if the display refresh rate is not a multiple of the
@@ -446,7 +462,7 @@
const std::vector<Fps> mKnownFrameRates;
const Config mConfig;
- bool mSupportsFrameRateOverrideByContent;
+ Config::FrameRateOverride mFrameRateOverrideConfig;
struct GetRankedRefreshRatesCache {
std::pair<std::vector<LayerRequirement>, GlobalSignals> arguments;
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/Fps.h b/services/surfaceflinger/Scheduler/include/scheduler/Fps.h
index d89f685..31b1d69 100644
--- a/services/surfaceflinger/Scheduler/include/scheduler/Fps.h
+++ b/services/surfaceflinger/Scheduler/include/scheduler/Fps.h
@@ -144,8 +144,16 @@
return !(lhs == rhs);
}
+inline unsigned operator/(Fps lhs, Fps rhs) {
+ return static_cast<unsigned>(std::ceil(lhs.getValue() / rhs.getValue()));
+}
+
} // namespace fps_approx_ops
+constexpr Fps operator/(Fps fps, unsigned divisor) {
+ return Fps::fromPeriodNsecs(fps.getPeriodNsecs() * static_cast<nsecs_t>(divisor));
+}
+
inline bool FpsRange::includes(Fps fps) const {
using fps_approx_ops::operator<=;
return min <= fps && fps <= max;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 2ca39d0..ee22ecc 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2777,8 +2777,21 @@
const auto [kernelIdleTimerController, idleTimerTimeoutMs] =
getKernelIdleTimerProperties(compositionDisplay->getId());
+ const auto enableFrameRateOverride = [&] {
+ using Config = scheduler::RefreshRateSelector::Config;
+ if (!sysprop::enable_frame_rate_override(false)) {
+ return Config::FrameRateOverride::Disabled;
+ }
+
+ if (sysprop::frame_rate_override_for_native_rates(true)) {
+ return Config::FrameRateOverride::EnabledForNativeRefreshRates;
+ }
+
+ return Config::FrameRateOverride::Enabled;
+ }();
+
scheduler::RefreshRateSelector::Config config =
- {.enableFrameRateOverride = android::sysprop::enable_frame_rate_override(false),
+ {.enableFrameRateOverride = enableFrameRateOverride,
.frameRateMultipleThreshold =
base::GetIntProperty("debug.sf.frame_rate_multiple_threshold", 0),
.idleTimerTimeout = idleTimerTimeoutMs,
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp
index 20fa091..c8c71df 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.cpp
+++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp
@@ -367,6 +367,10 @@
return SurfaceFlingerProperties::enable_frame_rate_override().value_or(defaultValue);
}
+bool frame_rate_override_for_native_rates(bool defaultValue) {
+ return SurfaceFlingerProperties::frame_rate_override_for_native_rates().value_or(defaultValue);
+}
+
bool enable_layer_caching(bool defaultValue) {
return SurfaceFlingerProperties::enable_layer_caching().value_or(defaultValue);
}
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h
index 080feee..5e316cf 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.h
+++ b/services/surfaceflinger/SurfaceFlingerProperties.h
@@ -96,6 +96,8 @@
bool enable_frame_rate_override(bool defaultValue);
+bool frame_rate_override_for_native_rates(bool defaultValue);
+
bool enable_layer_caching(bool defaultValue);
bool enable_sdr_dimming(bool defaultValue);
diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
index bcbe21a..28da81f 100644
--- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
+++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
@@ -445,6 +445,18 @@
prop_name: "ro.surface_flinger.enable_frame_rate_override"
}
+# Limits the frame rate override feature (enable_frame_rate_override) to override the refresh rate
+# to native display refresh rates only. Before introducing this flag, native display refresh rates
+# was the default behvaiour. With this flag we can control which behaviour we want explicitly.
+# This flag is intoruduced as a fail-safe machanism and planned to be defaulted to false.
+prop {
+ api_name: "frame_rate_override_for_native_rates"
+ type: Boolean
+ scope: Public
+ access: Readonly
+ prop_name: "ro.surface_flinger.frame_rate_override_for_native_rates"
+}
+
# Enables Layer Caching
prop {
api_name: "enable_layer_caching"
diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
index 348a462..0dfb80e 100644
--- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
+++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
@@ -61,6 +61,10 @@
prop_name: "ro.surface_flinger.force_hwc_copy_for_virtual_displays"
}
prop {
+ api_name: "frame_rate_override_for_native_rates"
+ prop_name: "ro.surface_flinger.frame_rate_override_for_native_rates"
+ }
+ prop {
api_name: "has_HDR_display"
prop_name: "ro.surface_flinger.has_HDR_display"
}
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
index 9689ddb..cedb7eb 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
@@ -37,6 +37,7 @@
namespace hal = android::hardware::graphics::composer::hal;
+using Config = RefreshRateSelector::Config;
using LayerRequirement = RefreshRateSelector::LayerRequirement;
using LayerVoteType = RefreshRateSelector::LayerVoteType;
using SetPolicyResult = RefreshRateSelector::SetPolicyResult;
@@ -2034,7 +2035,8 @@
TEST_F(RefreshRateSelectorTest, getBestRefreshRate_ExplicitExactEnableFrameRateOverride) {
TestableRefreshRateSelector selector(kModes_30_60_72_90_120, kModeId60,
- {.enableFrameRateOverride = true});
+ {.enableFrameRateOverride =
+ Config::FrameRateOverride::Enabled});
std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 0.5f}};
auto& explicitExactLayer = layers[0];
@@ -2100,7 +2102,8 @@
TEST_F(RefreshRateSelectorTest, getBestRefreshRate_ExplicitExactTouchBoost) {
TestableRefreshRateSelector selector(kModes_60_120, kModeId60,
- {.enableFrameRateOverride = true});
+ {.enableFrameRateOverride =
+ Config::FrameRateOverride::Enabled});
std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 0.5f}};
auto& explicitExactLayer = layers[0];
@@ -2125,7 +2128,8 @@
TEST_F(RefreshRateSelectorTest, getBestRefreshRate_FractionalRefreshRates_ExactAndDefault) {
TestableRefreshRateSelector selector(kModes_24_25_30_50_60_Frac, kModeId60,
- {.enableFrameRateOverride = true});
+ {.enableFrameRateOverride =
+ Config::FrameRateOverride::Enabled});
std::vector<LayerRequirement> layers = {{.weight = 0.5f}, {.weight = 0.5f}};
auto& explicitDefaultLayer = layers[0];
@@ -2319,7 +2323,7 @@
TEST_F(RefreshRateSelectorTest, getFrameRateOverrides_60on120) {
RefreshRateSelector selector(kModes_30_60_72_90_120, kModeId120,
- {.enableFrameRateOverride = true});
+ {.enableFrameRateOverride = Config::FrameRateOverride::Enabled});
std::vector<LayerRequirement> layers = {{.weight = 1.f}};
layers[0].name = "Test layer";
@@ -2357,7 +2361,7 @@
TEST_F(RefreshRateSelectorTest, getFrameRateOverrides_twoUids) {
RefreshRateSelector selector(kModes_30_60_72_90_120, kModeId120,
- {.enableFrameRateOverride = true});
+ {.enableFrameRateOverride = Config::FrameRateOverride::Enabled});
std::vector<LayerRequirement> layers = {{.ownerUid = 1234, .weight = 1.f},
{.ownerUid = 5678, .weight = 1.f}};
@@ -2390,7 +2394,7 @@
TEST_F(RefreshRateSelectorTest, getFrameRateOverrides_touch) {
RefreshRateSelector selector(kModes_30_60_72_90_120, kModeId120,
- {.enableFrameRateOverride = true});
+ {.enableFrameRateOverride = Config::FrameRateOverride::Enabled});
std::vector<LayerRequirement> layers = {{.ownerUid = 1234, .weight = 1.f}};
layers[0].name = "Test layer";
@@ -2428,5 +2432,139 @@
EXPECT_TRUE(frameRateOverrides.empty());
}
+TEST_F(RefreshRateSelectorTest, getFrameRateOverrides_DivisorIsNotDisplayRefreshRate_Enabled) {
+ RefreshRateSelector selector(kModes_60_120, kModeId120,
+ {.enableFrameRateOverride = Config::FrameRateOverride::Enabled});
+
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
+ layers[0].name = "Test layer";
+ layers[0].ownerUid = 1234;
+ layers[0].desiredRefreshRate = 30_Hz;
+ layers[0].vote = LayerVoteType::ExplicitDefault;
+
+ auto frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {});
+ EXPECT_EQ(1u, frameRateOverrides.size());
+ ASSERT_EQ(1u, frameRateOverrides.count(1234));
+ EXPECT_EQ(30_Hz, frameRateOverrides.at(1234));
+
+ layers[0].vote = LayerVoteType::ExplicitExactOrMultiple;
+ frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {});
+ EXPECT_EQ(1u, frameRateOverrides.size());
+ ASSERT_EQ(1u, frameRateOverrides.count(1234));
+ EXPECT_EQ(30_Hz, frameRateOverrides.at(1234));
+
+ layers[0].vote = LayerVoteType::NoVote;
+ frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {});
+ EXPECT_TRUE(frameRateOverrides.empty());
+
+ layers[0].vote = LayerVoteType::Min;
+ frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {});
+ EXPECT_TRUE(frameRateOverrides.empty());
+
+ layers[0].vote = LayerVoteType::Max;
+ frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {});
+ EXPECT_TRUE(frameRateOverrides.empty());
+
+ layers[0].vote = LayerVoteType::Heuristic;
+ frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {});
+ EXPECT_TRUE(frameRateOverrides.empty());
+}
+
+TEST_F(RefreshRateSelectorTest,
+ getFrameRateOverrides_DivisorIsNotDisplayRefreshRate_EnabledForNativeRefreshRates) {
+ RefreshRateSelector selector(kModes_60_120, kModeId120,
+ {.enableFrameRateOverride =
+ Config::FrameRateOverride::EnabledForNativeRefreshRates});
+
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
+ layers[0].name = "Test layer";
+ layers[0].ownerUid = 1234;
+ layers[0].desiredRefreshRate = 30_Hz;
+ layers[0].vote = LayerVoteType::ExplicitDefault;
+
+ auto frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {});
+ EXPECT_EQ(1u, frameRateOverrides.size());
+ ASSERT_EQ(1u, frameRateOverrides.count(1234));
+ EXPECT_EQ(60_Hz, frameRateOverrides.at(1234));
+
+ layers[0].vote = LayerVoteType::ExplicitExactOrMultiple;
+ frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {});
+ EXPECT_EQ(1u, frameRateOverrides.size());
+ ASSERT_EQ(1u, frameRateOverrides.count(1234));
+ EXPECT_EQ(60_Hz, frameRateOverrides.at(1234));
+
+ layers[0].vote = LayerVoteType::NoVote;
+ frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {});
+ EXPECT_TRUE(frameRateOverrides.empty());
+
+ layers[0].vote = LayerVoteType::Min;
+ frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {});
+ EXPECT_TRUE(frameRateOverrides.empty());
+
+ layers[0].vote = LayerVoteType::Max;
+ frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {});
+ EXPECT_TRUE(frameRateOverrides.empty());
+
+ layers[0].vote = LayerVoteType::Heuristic;
+ frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {});
+ EXPECT_TRUE(frameRateOverrides.empty());
+}
+
+TEST_F(RefreshRateSelectorTest, getFrameRateOverrides_InPolicy) {
+ TestableRefreshRateSelector selector(kModes_30_60_72_90_120, kModeId120,
+ {.enableFrameRateOverride =
+ Config::FrameRateOverride::Enabled});
+
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
+ {
+ const FpsRange physical = {120_Hz, 120_Hz};
+ const FpsRange render = {60_Hz, 90_Hz};
+ EXPECT_EQ(SetPolicyResult::Changed,
+ selector.setDisplayManagerPolicy(
+ {kModeId120, {physical, render}, {physical, render}}));
+ }
+
+ layers[0].name = "30Hz";
+ layers[0].ownerUid = 1234;
+ layers[0].desiredRefreshRate = 30_Hz;
+ layers[0].vote = LayerVoteType::ExplicitDefault;
+
+ auto frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {});
+ EXPECT_EQ(1u, frameRateOverrides.size());
+ EXPECT_EQ(1u, frameRateOverrides.count(1234));
+ EXPECT_EQ(60_Hz, frameRateOverrides.at(1234));
+
+ {
+ const FpsRange physical = {120_Hz, 120_Hz};
+ const FpsRange render = {30_Hz, 90_Hz};
+ EXPECT_EQ(SetPolicyResult::Changed,
+ selector.setDisplayManagerPolicy(
+ {kModeId120, {physical, render}, {physical, render}}));
+ }
+
+ frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {});
+ EXPECT_EQ(1u, frameRateOverrides.size());
+ EXPECT_EQ(1u, frameRateOverrides.count(1234));
+ EXPECT_EQ(30_Hz, frameRateOverrides.at(1234));
+
+ {
+ const FpsRange physical = {120_Hz, 120_Hz};
+ const FpsRange render = {30_Hz, 30_Hz};
+ EXPECT_EQ(SetPolicyResult::Changed,
+ selector.setDisplayManagerPolicy(
+ {kModeId120, {physical, render}, {physical, render}}));
+ }
+
+ layers[0].name = "60Hz";
+ layers[0].ownerUid = 1234;
+ layers[0].desiredRefreshRate = 60_Hz;
+ layers[0].vote = LayerVoteType::ExplicitDefault;
+
+ frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {});
+ EXPECT_EQ(1u, frameRateOverrides.size());
+ EXPECT_EQ(1u, frameRateOverrides.count(1234));
+ EXPECT_EQ(30_Hz, frameRateOverrides.at(1234));
+}
+
} // namespace
} // namespace android::scheduler