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/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);
}
}