Add sysprop for refresh rate threshold.
When the sysprop is enabled, layers asking for heuristic or multiple
will not vote for multiples >= $threshold amount. For example, 24 fps
would normally vote 120 hz because it is a multiple. Instead, it should
use the scoring calculation to determine a refresh rate < 120 Hz.
This addresses 24 fps videos for 60Hz and 120 Hz displays. The request
wants the refresh rate vote to be 60 Hz. (see bug)
BUG: 190815773
Test: atest libsurfaceflinger_tests
Change-Id: If2619258b93fb9c30e09253266d3d65e1a732047
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 0eb16e2..4f47ed8 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -107,9 +107,39 @@
return {quotient, remainder};
}
+bool RefreshRateConfigs::isVoteAllowed(const LayerRequirement& layer,
+ const RefreshRate& refreshRate) const {
+ switch (layer.vote) {
+ case LayerVoteType::ExplicitExactOrMultiple:
+ case LayerVoteType::Heuristic:
+ if (mConfig.frameRateMultipleThreshold != 0 &&
+ refreshRate.fps.greaterThanOrEqualWithMargin(
+ Fps(mConfig.frameRateMultipleThreshold)) &&
+ layer.desiredRefreshRate.lessThanWithMargin(
+ Fps(mConfig.frameRateMultipleThreshold / 2))) {
+ // Don't vote high refresh rates past the threshold for layers with a low desired
+ // refresh rate. For example, desired 24 fps with 120 Hz threshold means no vote for
+ // 120 Hz, but desired 60 fps should have a vote.
+ return false;
+ }
+ break;
+ case LayerVoteType::ExplicitDefault:
+ case LayerVoteType::ExplicitExact:
+ case LayerVoteType::Max:
+ case LayerVoteType::Min:
+ case LayerVoteType::NoVote:
+ break;
+ }
+ return true;
+}
+
float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& layer,
const RefreshRate& refreshRate,
bool isSeamlessSwitch) const {
+ if (!isVoteAllowed(layer, refreshRate)) {
+ return 0;
+ }
+
// Slightly prefer seamless switches.
constexpr float kSeamedSwitchPenalty = 0.95f;
const float seamlessness = isSeamlessSwitch ? 1.0f : kSeamedSwitchPenalty;
@@ -331,8 +361,9 @@
const auto& defaultMode = mRefreshRates.at(policy->defaultMode);
for (const auto& layer : layers) {
- ALOGV("Calculating score for %s (%s, weight %.2f)", layer.name.c_str(),
- layerVoteTypeString(layer.vote).c_str(), layer.weight);
+ ALOGV("Calculating score for %s (%s, weight %.2f, desired %.2f) ", layer.name.c_str(),
+ layerVoteTypeString(layer.vote).c_str(), layer.weight,
+ layer.desiredRefreshRate.getValue());
if (layer.vote == LayerVoteType::NoVote || layer.vote == LayerVoteType::Min) {
continue;
}
@@ -646,9 +677,8 @@
}
RefreshRateConfigs::RefreshRateConfigs(const DisplayModes& modes, DisplayModeId currentModeId,
- bool enableFrameRateOverride)
- : mKnownFrameRates(constructKnownFrameRates(modes)),
- mEnableFrameRateOverride(enableFrameRateOverride) {
+ Config config)
+ : mKnownFrameRates(constructKnownFrameRates(modes)), mConfig(config) {
updateDisplayModes(modes, currentModeId);
}
@@ -685,7 +715,7 @@
mMaxSupportedRefreshRate = sortedModes.back();
mSupportsFrameRateOverride = false;
- if (mEnableFrameRateOverride) {
+ if (mConfig.enableFrameRateOverride) {
for (const auto& mode1 : sortedModes) {
for (const auto& mode2 : sortedModes) {
if (getFrameRateDivider(mode1->getFps(), mode2->getFps()) >= 2) {
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 6cd0f42..0358e8c 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -53,7 +53,7 @@
public:
// Margin used when matching refresh rates to the content desired ones.
static constexpr nsecs_t MARGIN_FOR_PERIOD_CALCULATION =
- std::chrono::nanoseconds(800us).count();
+ std::chrono::nanoseconds(800us).count();
class RefreshRate {
private:
@@ -302,8 +302,19 @@
// Returns a known frame rate that is the closest to frameRate
Fps findClosestKnownFrameRate(Fps frameRate) const;
+ // Configuration flags.
+ struct Config {
+ bool enableFrameRateOverride = false;
+
+ // 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
+ // no threshold is set.
+ int frameRateMultipleThreshold = 0;
+ };
+
RefreshRateConfigs(const DisplayModes& modes, DisplayModeId currentModeId,
- bool enableFrameRateOverride = false);
+ Config config = {.enableFrameRateOverride = false,
+ .frameRateMultipleThreshold = 0});
void updateDisplayModes(const DisplayModes& mode, DisplayModeId currentModeId) EXCLUDES(mLock);
@@ -387,6 +398,9 @@
const Policy* getCurrentPolicyLocked() const REQUIRES(mLock);
bool isPolicyValidLocked(const Policy& policy) const REQUIRES(mLock);
+ // Returns whether the layer is allowed to vote for the given refresh rate.
+ bool isVoteAllowed(const LayerRequirement&, const RefreshRate&) const;
+
// calculates a score for a layer. Used to determine the display refresh rate
// and the frame rate override for certains applications.
float calculateLayerScoreLocked(const LayerRequirement&, const RefreshRate&,
@@ -424,7 +438,7 @@
// from based on the closest value.
const std::vector<Fps> mKnownFrameRates;
- const bool mEnableFrameRateOverride;
+ const Config mConfig;
bool mSupportsFrameRateOverride;
struct GetBestRefreshRateInvocation {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index f346465..e2f3ebb 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3118,10 +3118,15 @@
return;
}
const auto displayId = displayState.physical->id;
- mRefreshRateConfigs = std::make_unique<
- scheduler::RefreshRateConfigs>(displayState.physical->supportedModes,
- displayState.physical->activeMode->getId(),
- android::sysprop::enable_frame_rate_override(false));
+ scheduler::RefreshRateConfigs::Config config =
+ {.enableFrameRateOverride = android::sysprop::enable_frame_rate_override(false),
+ .frameRateMultipleThreshold =
+ base::GetIntProperty("debug.sf.frame_rate_multiple_threshold", 0)};
+ mRefreshRateConfigs =
+ std::make_unique<scheduler::RefreshRateConfigs>(displayState.physical->supportedModes,
+ displayState.physical->activeMode
+ ->getId(),
+ config);
const auto currRefreshRate = displayState.physical->activeMode->getFps();
mRefreshRateStats = std::make_unique<scheduler::RefreshRateStats>(*mTimeStats, currRefreshRate,
hal::PowerMode::OFF);
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index d4b229f..9bb5ca1 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -165,6 +165,7 @@
RefreshRate::ConstructorTag(0)};
RefreshRate mExpected120Config = {HWC_CONFIG_ID_120, mConfig120, Fps(120),
RefreshRate::ConstructorTag(0)};
+
private:
DisplayModePtr createDisplayMode(DisplayModeId modeId, int32_t group, int64_t vsyncPeriod,
ui::Size resolution = ui::Size());
@@ -487,6 +488,52 @@
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
}
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_multipleThreshold_60_90) {
+ RefreshRateConfigs::Config config = {.frameRateMultipleThreshold = 90};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m60_90Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_60, config);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ auto& lr = layers[0];
+
+ lr.vote = LayerVoteType::Min;
+ lr.name = "Min";
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.vote = LayerVoteType::Max;
+ lr.name = "Max";
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = Fps(90.0f);
+ lr.vote = LayerVoteType::Heuristic;
+ lr.name = "90Hz Heuristic";
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = Fps(60.0f);
+ lr.name = "60Hz Heuristic";
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = Fps(45.0f);
+ lr.name = "45Hz Heuristic";
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = Fps(30.0f);
+ lr.name = "30Hz Heuristic";
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = Fps(24.0f);
+ lr.name = "24Hz Heuristic";
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+}
+
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_60_72_90) {
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(m60_72_90Device,
@@ -649,6 +696,99 @@
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
}
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes_multipleThreshold) {
+ RefreshRateConfigs::Config config = {.frameRateMultipleThreshold = 120};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_60, config);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
+ LayerRequirement{.weight = 1.0f}};
+ auto& lr1 = layers[0];
+ auto& lr2 = layers[1];
+
+ lr1.desiredRefreshRate = Fps(24.0f);
+ lr1.vote = LayerVoteType::ExplicitDefault;
+ lr1.name = "24Hz ExplicitDefault";
+ lr2.desiredRefreshRate = Fps(60.0f);
+ lr2.vote = LayerVoteType::Heuristic;
+ lr2.name = "60Hz Heuristic";
+ EXPECT_EQ(mExpected120Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr1.desiredRefreshRate = Fps(24.0f);
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.name = "24Hz ExplicitExactOrMultiple";
+ lr2.desiredRefreshRate = Fps(60.0f);
+ lr2.vote = LayerVoteType::Heuristic;
+ lr2.name = "60Hz Heuristic";
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr1.desiredRefreshRate = Fps(24.0f);
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.name = "24Hz ExplicitExactOrMultiple";
+ lr2.desiredRefreshRate = Fps(60.0f);
+ lr2.vote = LayerVoteType::ExplicitDefault;
+ lr2.name = "60Hz ExplicitDefault";
+ EXPECT_EQ(mExpected72Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr1.desiredRefreshRate = Fps(24.0f);
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.name = "24Hz ExplicitExactOrMultiple";
+ lr2.desiredRefreshRate = Fps(90.0f);
+ lr2.vote = LayerVoteType::Heuristic;
+ lr2.name = "90Hz Heuristic";
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr1.desiredRefreshRate = Fps(24.0f);
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.name = "24Hz ExplicitExactOrMultiple";
+ lr2.desiredRefreshRate = Fps(90.0f);
+ lr2.vote = LayerVoteType::ExplicitDefault;
+ lr2.name = "90Hz Heuristic";
+ EXPECT_EQ(mExpected72Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr1.desiredRefreshRate = Fps(24.0f);
+ lr1.vote = LayerVoteType::ExplicitDefault;
+ lr1.name = "24Hz ExplicitDefault";
+ lr2.desiredRefreshRate = Fps(90.0f);
+ lr2.vote = LayerVoteType::Heuristic;
+ lr2.name = "90Hz Heuristic";
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr1.desiredRefreshRate = Fps(24.0f);
+ lr1.vote = LayerVoteType::Heuristic;
+ lr1.name = "24Hz Heuristic";
+ lr2.desiredRefreshRate = Fps(90.0f);
+ lr2.vote = LayerVoteType::ExplicitDefault;
+ lr2.name = "90Hz ExplicitDefault";
+ EXPECT_EQ(mExpected72Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr1.desiredRefreshRate = Fps(24.0f);
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.name = "24Hz ExplicitExactOrMultiple";
+ lr2.desiredRefreshRate = Fps(90.0f);
+ lr2.vote = LayerVoteType::ExplicitDefault;
+ lr2.name = "90Hz ExplicitDefault";
+ EXPECT_EQ(mExpected72Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr1.desiredRefreshRate = Fps(24.0f);
+ lr1.vote = LayerVoteType::ExplicitDefault;
+ lr1.name = "24Hz ExplicitDefault";
+ lr2.desiredRefreshRate = Fps(90.0f);
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr2.name = "90Hz ExplicitExactOrMultiple";
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+}
+
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60) {
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(m30_60Device,
@@ -819,6 +959,24 @@
}
}
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_24FpsVideo_multipleThreshold_60_120) {
+ RefreshRateConfigs::Config config = {.frameRateMultipleThreshold = 120};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m60_120Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_60, config);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ auto& lr = layers[0];
+
+ lr.vote = LayerVoteType::ExplicitExactOrMultiple;
+ for (float fps = 23.0f; fps < 25.0f; fps += 0.1f) {
+ lr.desiredRefreshRate = Fps(fps);
+ const auto& refreshRate =
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false});
+ EXPECT_EQ(mExpected60Config, refreshRate) << fps << "Hz chooses " << refreshRate.getName();
+ }
+}
+
TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getBestRefreshRate_Explicit) {
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(m60_90Device,
@@ -1732,10 +1890,10 @@
}
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExactEnableFrameRateOverride) {
+ RefreshRateConfigs::Config config = {.enableFrameRateOverride = true};
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device,
- /*currentConfigId=*/HWC_CONFIG_ID_60,
- /*enableFrameRateOverride=*/true);
+ /*currentConfigId=*/HWC_CONFIG_ID_60, config);
auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
LayerRequirement{.weight = 0.5f}};
@@ -1846,10 +2004,10 @@
}
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExactTouchBoost) {
+ RefreshRateConfigs::Config config = {.enableFrameRateOverride = true};
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(m60_120Device,
- /*currentConfigId=*/HWC_CONFIG_ID_60,
- /*enableFrameRateOverride=*/true);
+ /*currentConfigId=*/HWC_CONFIG_ID_60, config);
auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
LayerRequirement{.weight = 0.5f}};
@@ -1950,10 +2108,10 @@
}
TEST_F(RefreshRateConfigsTest, getFrameRateOverrides_60on120) {
+ RefreshRateConfigs::Config config = {.enableFrameRateOverride = true};
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device, /*currentConfigId=*/
- HWC_CONFIG_ID_120,
- /*enableFrameRateOverride=*/true);
+ HWC_CONFIG_ID_120, config);
auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
layers[0].name = "Test layer";
@@ -1995,10 +2153,10 @@
}
TEST_F(RefreshRateConfigsTest, getFrameRateOverrides_twoUids) {
+ RefreshRateConfigs::Config config = {.enableFrameRateOverride = true};
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device, /*currentConfigId=*/
- HWC_CONFIG_ID_120,
- /*enableFrameRateOverride=*/true);
+ HWC_CONFIG_ID_120, config);
auto layers = std::vector<LayerRequirement>{
LayerRequirement{.ownerUid = 1234, .weight = 1.0f},
@@ -2035,10 +2193,10 @@
}
TEST_F(RefreshRateConfigsTest, getFrameRateOverrides_touch) {
+ RefreshRateConfigs::Config config = {.enableFrameRateOverride = true};
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device, /*currentConfigId=*/
- HWC_CONFIG_ID_120,
- /*enableFrameRateOverride=*/true);
+ HWC_CONFIG_ID_120, config);
auto layers = std::vector<LayerRequirement>{
LayerRequirement{.ownerUid = 1234, .weight = 1.0f},