SF: prefer >=60Hz for fractional frame rates
If a layer requests a fractional frame rate that the display doesn't
naively support, favor at least 60Hz.
This is done by explicitly checking for known frame rates.
This change is needed to avoid selecting refresh rates such as 30Hz for
29.97fps content as it leads to frame drops.
Test: SF unit tests
Bug: 290839444
Bug: 292068399
Change-Id: I3dce623dd02b115323cb84f96e855d9010494a81
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
index b531972..c44e22e 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
@@ -302,6 +302,19 @@
if (layer.vote == LayerVoteType::ExplicitExactOrMultiple ||
layer.vote == LayerVoteType::Heuristic) {
+ using fps_approx_ops::operator<;
+ if (refreshRate < 60_Hz) {
+ const bool favorsAtLeast60 =
+ std::find_if(mFrameRatesThatFavorsAtLeast60.begin(),
+ mFrameRatesThatFavorsAtLeast60.end(), [&](Fps fps) {
+ using fps_approx_ops::operator==;
+ return fps == layer.desiredRefreshRate;
+ }) != mFrameRatesThatFavorsAtLeast60.end();
+ if (favorsAtLeast60) {
+ return 0;
+ }
+ }
+
const float multiplier = refreshRate.getValue() / layer.desiredRefreshRate.getValue();
// We only want to score this layer as a fractional pair if the content is not
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.h b/services/surfaceflinger/Scheduler/RefreshRateSelector.h
index 5052e6e..7af8d03 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.h
@@ -18,6 +18,7 @@
#include <algorithm>
#include <numeric>
+#include <set>
#include <type_traits>
#include <utility>
#include <variant>
@@ -500,6 +501,12 @@
const std::vector<Fps> mKnownFrameRates;
const Config mConfig;
+
+ // A list of known frame rates that favors at least 60Hz if there is no exact match display
+ // refresh rate
+ const std::vector<Fps> mFrameRatesThatFavorsAtLeast60 = {23.976_Hz, 25_Hz, 29.97_Hz, 50_Hz,
+ 59.94_Hz};
+
Config::FrameRateOverride mFrameRateOverrideConfig;
struct GetRankedFrameRatesCache {
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
index 646d9cc..aaf55fb 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
@@ -222,6 +222,7 @@
makeModes(kMode60, kMode90, kMode72_G1, kMode120_G1, kMode30_G1, kMode25_G1, kMode50);
static inline const DisplayModes kModes_60_120 = makeModes(kMode60, kMode120);
static inline const DisplayModes kModes_1_5_10 = makeModes(kMode1, kMode5, kMode10);
+ static inline const DisplayModes kModes_60_90_120 = makeModes(kMode60, kMode90, kMode120);
// This is a typical TV configuration.
static inline const DisplayModes kModes_24_25_30_50_60_Frac =
@@ -1413,7 +1414,9 @@
ss << "ExplicitDefault " << desired;
lr.name = ss.str();
- EXPECT_EQ(expected, selector.getBestFrameRateMode(layers)->getFps());
+ const auto bestFps = selector.getBestFrameRateMode(layers)->getFps();
+ EXPECT_EQ(expected, bestFps)
+ << "expected " << expected << " for " << desired << " but got " << bestFps;
}
}
@@ -1422,7 +1425,7 @@
std::vector<LayerRequirement> layers = {{.weight = 1.f}};
auto& lr = layers[0];
- // Test that 23.976 will choose 24 if 23.976 is not supported
+ // Test that 23.976 will prefer 60 over 59.94 and 30
{
auto selector = createSelector(makeModes(kMode24, kMode25, kMode30, kMode30Frac, kMode60,
kMode60Frac),
@@ -1431,7 +1434,7 @@
lr.vote = LayerVoteType::ExplicitExactOrMultiple;
lr.desiredRefreshRate = 23.976_Hz;
lr.name = "ExplicitExactOrMultiple 23.976 Hz";
- EXPECT_EQ(kModeId24, selector.getBestFrameRateMode(layers)->getId());
+ EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers)->getId());
}
// Test that 24 will choose 23.976 if 24 is not supported
@@ -1456,13 +1459,13 @@
EXPECT_EQ(kModeId60Frac, selector.getBestFrameRateMode(layers)->getId());
}
- // Test that 29.97 will choose 30 if 59.94 is not supported
+ // Test that 29.97 will choose 60 if 59.94 is not supported
{
auto selector = createSelector(makeModes(kMode30, kMode60), kModeId60);
lr.desiredRefreshRate = 29.97_Hz;
lr.name = "ExplicitExactOrMultiple 29.97 Hz";
- EXPECT_EQ(kModeId30, selector.getBestFrameRateMode(layers)->getId());
+ EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers)->getId());
}
// Test that 59.94 will choose 60 if 59.94 is not supported
@@ -2516,6 +2519,71 @@
EXPECT_FALSE(RefreshRateSelector::isFractionalPairOrMultiple(29.97_Hz, 59.94_Hz));
}
+TEST_P(RefreshRateSelectorTest, test23976Chooses120) {
+ auto selector = createSelector(kModes_60_90_120, kModeId120);
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
+ layers[0].name = "23.976 ExplicitExactOrMultiple";
+ layers[0].vote = LayerVoteType::ExplicitExactOrMultiple;
+ layers[0].desiredRefreshRate = 23.976_Hz;
+ EXPECT_FRAME_RATE_MODE(kMode120, 120_Hz, selector.getBestScoredFrameRate(layers).frameRateMode);
+}
+
+TEST_P(RefreshRateSelectorTest, test23976Chooses60IfThresholdIs120) {
+ auto selector =
+ createSelector(kModes_60_90_120, kModeId120, {.frameRateMultipleThreshold = 120});
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
+ layers[0].name = "23.976 ExplicitExactOrMultiple";
+ layers[0].vote = LayerVoteType::ExplicitExactOrMultiple;
+ layers[0].desiredRefreshRate = 23.976_Hz;
+ EXPECT_FRAME_RATE_MODE(kMode60, 60_Hz, selector.getBestScoredFrameRate(layers).frameRateMode);
+}
+
+TEST_P(RefreshRateSelectorTest, test25Chooses60) {
+ auto selector = createSelector(kModes_60_90_120, kModeId120);
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
+ layers[0].name = "25 ExplicitExactOrMultiple";
+ layers[0].vote = LayerVoteType::ExplicitExactOrMultiple;
+ layers[0].desiredRefreshRate = 25.00_Hz;
+ EXPECT_FRAME_RATE_MODE(kMode60, 60_Hz, selector.getBestScoredFrameRate(layers).frameRateMode);
+}
+
+TEST_P(RefreshRateSelectorTest, test2997Chooses60) {
+ auto selector = createSelector(kModes_60_90_120, kModeId120);
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
+ layers[0].name = "29.97 ExplicitExactOrMultiple";
+ layers[0].vote = LayerVoteType::ExplicitExactOrMultiple;
+ layers[0].desiredRefreshRate = 29.97_Hz;
+ EXPECT_FRAME_RATE_MODE(kMode60, 60_Hz, selector.getBestScoredFrameRate(layers).frameRateMode);
+}
+
+TEST_P(RefreshRateSelectorTest, test50Chooses120) {
+ auto selector = createSelector(kModes_60_90_120, kModeId120);
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
+ layers[0].name = "50 ExplicitExactOrMultiple";
+ layers[0].vote = LayerVoteType::ExplicitExactOrMultiple;
+ layers[0].desiredRefreshRate = 50.00_Hz;
+ EXPECT_FRAME_RATE_MODE(kMode120, 120_Hz, selector.getBestScoredFrameRate(layers).frameRateMode);
+}
+
+TEST_P(RefreshRateSelectorTest, test50Chooses60IfThresholdIs120) {
+ auto selector =
+ createSelector(kModes_60_90_120, kModeId120, {.frameRateMultipleThreshold = 120});
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
+ layers[0].name = "50 ExplicitExactOrMultiple";
+ layers[0].vote = LayerVoteType::ExplicitExactOrMultiple;
+ layers[0].desiredRefreshRate = 50.00_Hz;
+ EXPECT_FRAME_RATE_MODE(kMode60, 60_Hz, selector.getBestScoredFrameRate(layers).frameRateMode);
+}
+
+TEST_P(RefreshRateSelectorTest, test5994Chooses60) {
+ auto selector = createSelector(kModes_60_90_120, kModeId120);
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
+ layers[0].name = "59.94 ExplicitExactOrMultiple";
+ layers[0].vote = LayerVoteType::ExplicitExactOrMultiple;
+ layers[0].desiredRefreshRate = 59.94_Hz;
+ EXPECT_FRAME_RATE_MODE(kMode60, 60_Hz, selector.getBestScoredFrameRate(layers).frameRateMode);
+}
+
TEST_P(RefreshRateSelectorTest, getFrameRateOverrides_noLayers) {
auto selector = createSelector(kModes_30_60_72_90_120, kModeId120);