Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6429b0b3 authored by Dominik Laskowski's avatar Dominik Laskowski
Browse files

SF: Clean up DisplayModeSwitchingTest

Use the ModeSettledTo and ModeSwitchingTo helpers in all tests. Clean up
tests for brevity (e.g. minimal mock::createDisplayModeSpecs parameters)
and consistency (e.g. NO_ERROR checks).

Flag: TEST_ONLY
Bug: 241285876
Test: DisplayModeSwitchingTest
Change-Id: I5d92eae231d1b1a2c25f89ea7de4987569d9905e
parent b72c3fec
Loading
Loading
Loading
Loading
+99 −142
Original line number Diff line number Diff line
@@ -42,6 +42,47 @@ namespace {
using android::hardware::graphics::composer::V2_4::Error;
using android::hardware::graphics::composer::V2_4::VsyncPeriodChangeTimeline;

MATCHER_P2(ModeSettledTo, dmc, modeId, "") {
    const auto displayId = arg->getPhysicalId();

    if (const auto desiredOpt = dmc->getDesiredMode(displayId)) {
        *result_listener << "Unsettled desired mode "
                         << ftl::to_underlying(desiredOpt->mode.modePtr->getId());
        return false;
    }

    if (dmc->getActiveMode(displayId).modePtr->getId() != modeId) {
        *result_listener << "Settled to unexpected active mode " << ftl::to_underlying(modeId);
        return false;
    }

    return true;
}

MATCHER_P2(ModeSwitchingTo, flinger, modeId, "") {
    const auto displayId = arg->getPhysicalId();
    auto& dmc = flinger->mutableDisplayModeController();

    if (!dmc.getDesiredMode(displayId)) {
        *result_listener << "No desired mode";
        return false;
    }

    if (dmc.getDesiredMode(displayId)->mode.modePtr->getId() != modeId) {
        *result_listener << "Unexpected desired mode " << ftl::to_underlying(modeId);
        return false;
    }

    // VsyncModulator should react to mode switches on the pacesetter display.
    if (displayId == flinger->scheduler()->pacesetterDisplayId() &&
        !flinger->scheduler()->vsyncModulator().isVsyncConfigEarly()) {
        *result_listener << "VsyncModulator did not shift to early phase";
        return false;
    }

    return true;
}

class DisplayModeSwitchingTest : public DisplayTransactionTest {
public:
    void SetUp() override {
@@ -58,8 +99,7 @@ public:

        setupScheduler(selectorPtr);

        mFlinger.onComposerHalHotplugEvent(PrimaryDisplayVariant::HWC_DISPLAY_ID,
                                           DisplayHotplugEvent::CONNECTED);
        mFlinger.onComposerHalHotplugEvent(kInnerDisplayHwcId, DisplayHotplugEvent::CONNECTED);
        mFlinger.configureAndCommit();

        auto vsyncController = std::make_unique<mock::VsyncController>();
@@ -90,6 +130,11 @@ public:
    auto injectOuterDisplay() {
        constexpr PhysicalDisplayId kOuterDisplayId = PhysicalDisplayId::fromPort(254u);

        // For the inner display, this is handled by setupHwcHotplugCallExpectations.
        EXPECT_CALL(*mComposer, getDisplayConnectionType(kOuterDisplayHwcId, _))
                .WillOnce(DoAll(SetArgPointee<1>(IComposerClient::DisplayConnectionType::INTERNAL),
                                Return(hal::V2_4::Error::NONE)));

        constexpr bool kIsPrimary = false;
        TestableSurfaceFlinger::FakeHwcDisplayInjector(kOuterDisplayId, hal::DisplayType::PHYSICAL,
                                                       kIsPrimary)
@@ -169,129 +214,107 @@ void DisplayModeSwitchingTest::setupScheduler(
                            TestableSurfaceFlinger::SchedulerCallbackImpl::kNoOp);
}

TEST_F(DisplayModeSwitchingTest, changeRefreshRateOnActiveDisplayWithRefreshRequired) {
    ftl::FakeGuard guard(kMainThreadContext);

    EXPECT_FALSE(dmc().getDesiredMode(mDisplayId));
    EXPECT_EQ(dmc().getActiveMode(mDisplayId).modePtr->getId(), kModeId60);

    mFlinger.onActiveDisplayChanged(nullptr, *mDisplay);
TEST_F(DisplayModeSwitchingTest, changeRefreshRateWithRefreshRequired) {
    EXPECT_THAT(mDisplay, ModeSettledTo(&dmc(), kModeId60));

    EXPECT_EQ(NO_ERROR,
              mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(),
                                        mock::createDisplayModeSpecs(kModeId90, false, 0, 120));
                                                  mock::createDisplayModeSpecs(kModeId90, 120_Hz)));

    ASSERT_TRUE(dmc().getDesiredMode(mDisplayId));
    EXPECT_EQ(dmc().getDesiredMode(mDisplayId)->mode.modePtr->getId(), kModeId90);
    EXPECT_EQ(dmc().getActiveMode(mDisplayId).modePtr->getId(), kModeId60);
    EXPECT_THAT(mDisplay, ModeSwitchingTo(&mFlinger, kModeId90));

    // Verify that next commit will call setActiveConfigWithConstraints in HWC
    const VsyncPeriodChangeTimeline timeline{.refreshRequired = true};
    EXPECT_SET_ACTIVE_CONFIG(PrimaryDisplayVariant::HWC_DISPLAY_ID, kModeId90);
    EXPECT_SET_ACTIVE_CONFIG(kInnerDisplayHwcId, kModeId90);

    mFlinger.commit();

    Mock::VerifyAndClearExpectations(mComposer);

    EXPECT_TRUE(dmc().getDesiredMode(mDisplayId));
    EXPECT_EQ(dmc().getActiveMode(mDisplayId).modePtr->getId(), kModeId60);
    EXPECT_THAT(mDisplay, ModeSwitchingTo(&mFlinger, kModeId90));

    // Verify that the next commit will complete the mode change and send
    // a onModeChanged event to the framework.

    EXPECT_CALL(*mAppEventThread,
                onModeChanged(scheduler::FrameRateMode{90_Hz, ftl::as_non_null(kMode90)}));

    mFlinger.commit();
    Mock::VerifyAndClearExpectations(mAppEventThread);

    EXPECT_FALSE(dmc().getDesiredMode(mDisplayId));
    EXPECT_EQ(dmc().getActiveMode(mDisplayId).modePtr->getId(), kModeId90);
    EXPECT_THAT(mDisplay, ModeSettledTo(&dmc(), kModeId90));
}

TEST_F(DisplayModeSwitchingTest, changeRefreshRateOnActiveDisplayWithoutRefreshRequired) {
    ftl::FakeGuard guard(kMainThreadContext);

    EXPECT_FALSE(dmc().getDesiredMode(mDisplayId));

    mFlinger.onActiveDisplayChanged(nullptr, *mDisplay);
TEST_F(DisplayModeSwitchingTest, changeRefreshRateWithoutRefreshRequired) {
    EXPECT_THAT(mDisplay, ModeSettledTo(&dmc(), kModeId60));

    mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(),
                                        mock::createDisplayModeSpecs(kModeId90, true, 0, 120));
    constexpr bool kAllowGroupSwitching = true;
    EXPECT_EQ(NO_ERROR,
              mFlinger.setDesiredDisplayModeSpecs(
                      mDisplay->getDisplayToken().promote(),
                      mock::createDisplayModeSpecs(kModeId90, 120_Hz, kAllowGroupSwitching)));

    ASSERT_TRUE(dmc().getDesiredMode(mDisplayId));
    EXPECT_EQ(dmc().getDesiredMode(mDisplayId)->mode.modePtr->getId(), kModeId90);
    EXPECT_EQ(dmc().getActiveMode(mDisplayId).modePtr->getId(), kModeId60);
    EXPECT_THAT(mDisplay, ModeSwitchingTo(&mFlinger, kModeId90));

    // Verify that next commit will call setActiveConfigWithConstraints in HWC
    // and complete the mode change.
    const VsyncPeriodChangeTimeline timeline{.refreshRequired = false};
    EXPECT_SET_ACTIVE_CONFIG(PrimaryDisplayVariant::HWC_DISPLAY_ID, kModeId90);
    EXPECT_SET_ACTIVE_CONFIG(kInnerDisplayHwcId, kModeId90);

    EXPECT_CALL(*mAppEventThread,
                onModeChanged(scheduler::FrameRateMode{90_Hz, ftl::as_non_null(kMode90)}));

    mFlinger.commit();

    EXPECT_FALSE(dmc().getDesiredMode(mDisplayId));
    EXPECT_EQ(dmc().getActiveMode(mDisplayId).modePtr->getId(), kModeId90);
    EXPECT_THAT(mDisplay, ModeSettledTo(&dmc(), kModeId90));
}

TEST_F(DisplayModeSwitchingTest, twoConsecutiveSetDesiredDisplayModeSpecs) {
    ftl::FakeGuard guard(kMainThreadContext);

    // Test that if we call setDesiredDisplayModeSpecs while a previous mode change
    // is still being processed the later call will be respected.

    EXPECT_FALSE(dmc().getDesiredMode(mDisplayId));
    EXPECT_EQ(dmc().getActiveMode(mDisplayId).modePtr->getId(), kModeId60);

    mFlinger.onActiveDisplayChanged(nullptr, *mDisplay);
    EXPECT_THAT(mDisplay, ModeSettledTo(&dmc(), kModeId60));

    EXPECT_EQ(NO_ERROR,
              mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(),
                                        mock::createDisplayModeSpecs(kModeId90, false, 0, 120));
                                                  mock::createDisplayModeSpecs(kModeId90, 120_Hz)));

    const VsyncPeriodChangeTimeline timeline{.refreshRequired = true};
    EXPECT_SET_ACTIVE_CONFIG(PrimaryDisplayVariant::HWC_DISPLAY_ID, kModeId90);
    EXPECT_SET_ACTIVE_CONFIG(kInnerDisplayHwcId, kModeId90);

    mFlinger.commit();

    EXPECT_EQ(NO_ERROR,
              mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(),
                                        mock::createDisplayModeSpecs(kModeId120, false, 0, 180));
                                                  mock::createDisplayModeSpecs(kModeId120,
                                                                               180_Hz)));

    ASSERT_TRUE(dmc().getDesiredMode(mDisplayId));
    EXPECT_EQ(dmc().getDesiredMode(mDisplayId)->mode.modePtr->getId(), kModeId120);
    EXPECT_THAT(mDisplay, ModeSwitchingTo(&mFlinger, kModeId120));

    EXPECT_SET_ACTIVE_CONFIG(PrimaryDisplayVariant::HWC_DISPLAY_ID, kModeId120);
    EXPECT_SET_ACTIVE_CONFIG(kInnerDisplayHwcId, kModeId120);

    mFlinger.commit();

    ASSERT_TRUE(dmc().getDesiredMode(mDisplayId));
    EXPECT_EQ(dmc().getDesiredMode(mDisplayId)->mode.modePtr->getId(), kModeId120);
    EXPECT_THAT(mDisplay, ModeSwitchingTo(&mFlinger, kModeId120));

    mFlinger.commit();

    EXPECT_FALSE(dmc().getDesiredMode(mDisplayId));
    EXPECT_EQ(dmc().getActiveMode(mDisplayId).modePtr->getId(), kModeId120);
    EXPECT_THAT(mDisplay, ModeSettledTo(&dmc(), kModeId120));
}

TEST_F(DisplayModeSwitchingTest, changeResolutionOnActiveDisplayWithoutRefreshRequired) {
    ftl::FakeGuard guard(kMainThreadContext);

    EXPECT_FALSE(dmc().getDesiredMode(mDisplayId));
    EXPECT_EQ(dmc().getActiveMode(mDisplayId).modePtr->getId(), kModeId60);

    mFlinger.onActiveDisplayChanged(nullptr, *mDisplay);
TEST_F(DisplayModeSwitchingTest, changeResolutionWithoutRefreshRequired) {
    EXPECT_THAT(mDisplay, ModeSettledTo(&dmc(), kModeId60));

    EXPECT_EQ(NO_ERROR,
              mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(),
                                        mock::createDisplayModeSpecs(kModeId90_4K, false, 0, 120));
                                                  mock::createDisplayModeSpecs(kModeId90_4K,
                                                                               120_Hz)));

    ASSERT_TRUE(dmc().getDesiredMode(mDisplayId));
    EXPECT_EQ(dmc().getDesiredMode(mDisplayId)->mode.modePtr->getId(), kModeId90_4K);
    EXPECT_EQ(dmc().getActiveMode(mDisplayId).modePtr->getId(), kModeId60);
    EXPECT_THAT(mDisplay, ModeSwitchingTo(&mFlinger, kModeId90_4K));

    // Verify that next commit will call setActiveConfigWithConstraints in HWC
    // and complete the mode change.
    const VsyncPeriodChangeTimeline timeline{.refreshRequired = false};
    EXPECT_SET_ACTIVE_CONFIG(PrimaryDisplayVariant::HWC_DISPLAY_ID, kModeId90_4K);
    EXPECT_SET_ACTIVE_CONFIG(kInnerDisplayHwcId, kModeId90_4K);

    EXPECT_CALL(*mAppEventThread, onHotplugReceived(mDisplayId, true));

@@ -310,61 +333,12 @@ TEST_F(DisplayModeSwitchingTest, changeResolutionOnActiveDisplayWithoutRefreshRe

    mFlinger.commit();

    EXPECT_FALSE(dmc().getDesiredMode(mDisplayId));
    EXPECT_EQ(dmc().getActiveMode(mDisplayId).modePtr->getId(), kModeId90_4K);
}

MATCHER_P2(ModeSwitchingTo, flinger, modeId, "") {
    const auto displayId = arg->getPhysicalId();
    auto& dmc = flinger->mutableDisplayModeController();

    if (!dmc.getDesiredMode(displayId)) {
        *result_listener << "No desired mode";
        return false;
    }

    if (dmc.getDesiredMode(displayId)->mode.modePtr->getId() != modeId) {
        *result_listener << "Unexpected desired mode " << ftl::to_underlying(modeId);
        return false;
    }

    // VsyncModulator should react to mode switches on the pacesetter display.
    if (displayId == flinger->scheduler()->pacesetterDisplayId() &&
        !flinger->scheduler()->vsyncModulator().isVsyncConfigEarly()) {
        *result_listener << "VsyncModulator did not shift to early phase";
        return false;
    }

    return true;
}

MATCHER_P2(ModeSettledTo, dmc, modeId, "") {
    const auto displayId = arg->getPhysicalId();

    if (const auto desiredOpt = dmc->getDesiredMode(displayId)) {
        *result_listener << "Unsettled desired mode "
                         << ftl::to_underlying(desiredOpt->mode.modePtr->getId());
        return false;
    }

    ftl::FakeGuard guard(kMainThreadContext);

    if (dmc->getActiveMode(displayId).modePtr->getId() != modeId) {
        *result_listener << "Settled to unexpected active mode " << ftl::to_underlying(modeId);
        return false;
    }

    return true;
    EXPECT_THAT(mDisplay, ModeSettledTo(&dmc(), kModeId90_4K));
}

TEST_F(DisplayModeSwitchingTest, innerXorOuterDisplay) {
    SET_FLAG_FOR_TEST(flags::connected_display, true);

    // For the inner display, this is handled by setupHwcHotplugCallExpectations.
    EXPECT_CALL(*mComposer, getDisplayConnectionType(kOuterDisplayHwcId, _))
            .WillOnce(DoAll(SetArgPointee<1>(IComposerClient::DisplayConnectionType::INTERNAL),
                            Return(hal::V2_4::Error::NONE)));

    const auto [innerDisplay, outerDisplay] = injectOuterDisplay();

    EXPECT_TRUE(innerDisplay->isPoweredOn());
@@ -381,13 +355,11 @@ TEST_F(DisplayModeSwitchingTest, innerXorOuterDisplay) {

    EXPECT_EQ(NO_ERROR,
              mFlinger.setDesiredDisplayModeSpecs(innerDisplay->getDisplayToken().promote(),
                                                  mock::createDisplayModeSpecs(kModeId90, false,
                                                                               0.f, 120.f)));
                                                  mock::createDisplayModeSpecs(kModeId90, 120_Hz)));

    EXPECT_EQ(NO_ERROR,
              mFlinger.setDesiredDisplayModeSpecs(outerDisplay->getDisplayToken().promote(),
                                                  mock::createDisplayModeSpecs(kModeId60, false,
                                                                               0.f, 120.f)));
                                                  mock::createDisplayModeSpecs(kModeId60, 120_Hz)));

    EXPECT_THAT(innerDisplay, ModeSwitchingTo(&mFlinger, kModeId90));
    EXPECT_THAT(outerDisplay, ModeSwitchingTo(&mFlinger, kModeId60));
@@ -414,8 +386,7 @@ TEST_F(DisplayModeSwitchingTest, innerXorOuterDisplay) {

    EXPECT_EQ(NO_ERROR,
              mFlinger.setDesiredDisplayModeSpecs(innerDisplay->getDisplayToken().promote(),
                                                  mock::createDisplayModeSpecs(kModeId60, false,
                                                                               0.f, 120.f)));
                                                  mock::createDisplayModeSpecs(kModeId60, 120_Hz)));

    EXPECT_THAT(innerDisplay, ModeSwitchingTo(&mFlinger, kModeId60));
    EXPECT_SET_ACTIVE_CONFIG(kInnerDisplayHwcId, kModeId60);
@@ -434,10 +405,6 @@ TEST_F(DisplayModeSwitchingTest, innerXorOuterDisplay) {
TEST_F(DisplayModeSwitchingTest, innerAndOuterDisplay) {
    SET_FLAG_FOR_TEST(flags::connected_display, true);

    // For the inner display, this is handled by setupHwcHotplugCallExpectations.
    EXPECT_CALL(*mComposer, getDisplayConnectionType(kOuterDisplayHwcId, _))
            .WillOnce(DoAll(SetArgPointee<1>(IComposerClient::DisplayConnectionType::INTERNAL),
                            Return(hal::V2_4::Error::NONE)));
    const auto [innerDisplay, outerDisplay] = injectOuterDisplay();

    EXPECT_TRUE(innerDisplay->isPoweredOn());
@@ -454,13 +421,11 @@ TEST_F(DisplayModeSwitchingTest, innerAndOuterDisplay) {

    EXPECT_EQ(NO_ERROR,
              mFlinger.setDesiredDisplayModeSpecs(innerDisplay->getDisplayToken().promote(),
                                                  mock::createDisplayModeSpecs(kModeId90, false,
                                                                               0.f, 120.f)));
                                                  mock::createDisplayModeSpecs(kModeId90, 120_Hz)));

    EXPECT_EQ(NO_ERROR,
              mFlinger.setDesiredDisplayModeSpecs(outerDisplay->getDisplayToken().promote(),
                                                  mock::createDisplayModeSpecs(kModeId60, false,
                                                                               0.f, 120.f)));
                                                  mock::createDisplayModeSpecs(kModeId60, 120_Hz)));

    EXPECT_THAT(innerDisplay, ModeSwitchingTo(&mFlinger, kModeId90));
    EXPECT_THAT(outerDisplay, ModeSwitchingTo(&mFlinger, kModeId60));
@@ -486,8 +451,7 @@ TEST_F(DisplayModeSwitchingTest, powerOffDuringModeSet) {

    EXPECT_EQ(NO_ERROR,
              mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(),
                                                  mock::createDisplayModeSpecs(kModeId90, false,
                                                                               0.f, 120.f)));
                                                  mock::createDisplayModeSpecs(kModeId90, 120_Hz)));

    EXPECT_THAT(mDisplay, ModeSwitchingTo(&mFlinger, kModeId90));

@@ -511,11 +475,6 @@ TEST_F(DisplayModeSwitchingTest, powerOffDuringModeSet) {
TEST_F(DisplayModeSwitchingTest, powerOffDuringConcurrentModeSet) {
    SET_FLAG_FOR_TEST(flags::connected_display, true);

    // For the inner display, this is handled by setupHwcHotplugCallExpectations.
    EXPECT_CALL(*mComposer, getDisplayConnectionType(kOuterDisplayHwcId, _))
            .WillOnce(DoAll(SetArgPointee<1>(IComposerClient::DisplayConnectionType::INTERNAL),
                            Return(hal::V2_4::Error::NONE)));

    const auto [innerDisplay, outerDisplay] = injectOuterDisplay();

    EXPECT_TRUE(innerDisplay->isPoweredOn());
@@ -532,13 +491,11 @@ TEST_F(DisplayModeSwitchingTest, powerOffDuringConcurrentModeSet) {

    EXPECT_EQ(NO_ERROR,
              mFlinger.setDesiredDisplayModeSpecs(innerDisplay->getDisplayToken().promote(),
                                                  mock::createDisplayModeSpecs(kModeId90, false,
                                                                               0.f, 120.f)));
                                                  mock::createDisplayModeSpecs(kModeId90, 120_Hz)));

    EXPECT_EQ(NO_ERROR,
              mFlinger.setDesiredDisplayModeSpecs(outerDisplay->getDisplayToken().promote(),
                                                  mock::createDisplayModeSpecs(kModeId60, false,
                                                                               0.f, 120.f)));
                                                  mock::createDisplayModeSpecs(kModeId60, 120_Hz)));

    EXPECT_THAT(innerDisplay, ModeSwitchingTo(&mFlinger, kModeId90));
    EXPECT_THAT(outerDisplay, ModeSwitchingTo(&mFlinger, kModeId60));
@@ -566,8 +523,8 @@ TEST_F(DisplayModeSwitchingTest, powerOffDuringConcurrentModeSet) {

    EXPECT_EQ(NO_ERROR,
              mFlinger.setDesiredDisplayModeSpecs(outerDisplay->getDisplayToken().promote(),
                                                  mock::createDisplayModeSpecs(kModeId120, false,
                                                                               0.f, 120.f)));
                                                  mock::createDisplayModeSpecs(kModeId120,
                                                                               120_Hz)));

    EXPECT_SET_ACTIVE_CONFIG(kOuterDisplayHwcId, kModeId120);

+4 −5
Original line number Diff line number Diff line
@@ -22,14 +22,13 @@

namespace android::mock {

inline gui::DisplayModeSpecs createDisplayModeSpecs(DisplayModeId defaultMode,
                                                    bool allowGroupSwitching, float minFps,
                                                    float maxFps) {
inline gui::DisplayModeSpecs createDisplayModeSpecs(DisplayModeId defaultMode, Fps maxFps,
                                                    bool allowGroupSwitching = false) {
    gui::DisplayModeSpecs specs;
    specs.defaultMode = ftl::to_underlying(defaultMode);
    specs.allowGroupSwitching = allowGroupSwitching;
    specs.primaryRanges.physical.min = minFps;
    specs.primaryRanges.physical.max = maxFps;
    specs.primaryRanges.physical.min = 0.f;
    specs.primaryRanges.physical.max = maxFps.getValue();
    specs.primaryRanges.render = specs.primaryRanges.physical;
    specs.appRequestRanges = specs.primaryRanges;
    return specs;