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

Commit 2cde1001 authored by Marin Shalamanov's avatar Marin Shalamanov
Browse files

SF: Always create LayerHistory in Scheduler

Currently if Scheduler is created when there is
only one supported display mode, LayerHistory is
not created. This optimization assumes that the
list of supported modes is never going to change
but this is not the case for TV devices.

The typical use case is when a TV dongle or
set-top box is first connected to a display
after it boots. In this cas some devices will
first report only one display mode and later
update to the full list of supported modes.

This CL changes the behaviour to always have an instance
of LayerHistory. If there's only one display mode
recordLayerHistory() and chooseRefreshRateForContent()
are noops.

The alternative to create LayerHistory on demand is
more cumbersome because we also would need to register
all already created layers.

Bug: 188872896
Test: presubmit
Change-Id: Ia236fd4a81cc736c172220ff60762ddbc3cbb83a
parent 993ddf4a
Loading
Loading
Loading
Loading
+7 −21
Original line number Diff line number Diff line
@@ -194,8 +194,6 @@ Scheduler::VsyncSchedule Scheduler::createVsyncSchedule(bool supportKernelTimer)

std::unique_ptr<LayerHistory> Scheduler::createLayerHistory(
        const scheduler::RefreshRateConfigs& configs) {
    if (!configs.canSwitch()) return nullptr;

    return std::make_unique<scheduler::LayerHistory>(configs);
}

@@ -579,8 +577,6 @@ void Scheduler::setIgnorePresentFences(bool ignore) {
}

void Scheduler::registerLayer(Layer* layer) {
    if (!mLayerHistory) return;

    scheduler::LayerHistory::LayerVoteType voteType;

    if (!mOptions.useContentDetection ||
@@ -600,26 +596,22 @@ void Scheduler::registerLayer(Layer* layer) {
}

void Scheduler::deregisterLayer(Layer* layer) {
    if (mLayerHistory) {
    mLayerHistory->deregisterLayer(layer);
}
}

void Scheduler::recordLayerHistory(Layer* layer, nsecs_t presentTime,
                                   LayerHistory::LayerUpdateType updateType) {
    if (mLayerHistory) {
    if (mRefreshRateConfigs.canSwitch()) {
        mLayerHistory->record(layer, presentTime, systemTime(), updateType);
    }
}

void Scheduler::setModeChangePending(bool pending) {
    if (mLayerHistory) {
    mLayerHistory->setModeChangePending(pending);
}
}

void Scheduler::chooseRefreshRateForContent() {
    if (!mLayerHistory) return;
    if (!mRefreshRateConfigs.canSwitch()) return;

    ATRACE_CALL();

@@ -691,10 +683,8 @@ void Scheduler::setDisplayPowerState(bool normal) {

    // Display Power event will boost the refresh rate to performance.
    // Clear Layer History to get fresh FPS detection
    if (mLayerHistory) {
    mLayerHistory->clear();
}
}

void Scheduler::kernelIdleTimerCallback(TimerState state) {
    ATRACE_INT("ExpiredKernelIdleTimer", static_cast<int>(state));
@@ -732,10 +722,8 @@ void Scheduler::touchTimerCallback(TimerState state) {
    // NOTE: Instead of checking all the layers, we should be checking the layer
    // that is currently on top. b/142507166 will give us this capability.
    if (handleTimerStateChanged(&mFeatures.touch, touch)) {
        if (mLayerHistory) {
        mLayerHistory->clear();
    }
    }
    ATRACE_INT("TouchState", static_cast<int>(touch));
}

@@ -908,10 +896,8 @@ void Scheduler::onDisplayRefreshed(nsecs_t timestamp) {
}

void Scheduler::onPrimaryDisplayAreaChanged(uint32_t displayArea) {
    if (mLayerHistory) {
    mLayerHistory->setDisplayArea(displayArea);
}
}

void Scheduler::setPreferredRefreshRateForUid(FrameRateOverride frameRateOverride) {
    if (frameRateOverride.frameRateHz > 0.f && frameRateOverride.frameRateHz < 1.f) {
+1 −1
Original line number Diff line number Diff line
@@ -268,7 +268,7 @@ private:
    VsyncSchedule mVsyncSchedule;

    // Used to choose refresh rate if content detection is enabled.
    const std::unique_ptr<LayerHistory> mLayerHistory;
    std::unique_ptr<LayerHistory> mLayerHistory;

    // Timer that records time between requests for next vsync.
    std::optional<scheduler::OneShotTimer> mIdleTimer;
+29 −9
Original line number Diff line number Diff line
@@ -51,9 +51,18 @@ protected:

    SchedulerTest();

    const scheduler::RefreshRateConfigs
            mConfigs{{DisplayMode::Builder(0).setVsyncPeriod(16'666'667).setGroup(0).build()},
                     DisplayModeId(0)};
    const DisplayModePtr mode60 = DisplayMode::Builder(0)
                                          .setId(DisplayModeId(0))
                                          .setVsyncPeriod(Fps(60.f).getPeriodNsecs())
                                          .setGroup(0)
                                          .build();
    const DisplayModePtr mode120 = DisplayMode::Builder(1)
                                           .setId(DisplayModeId(1))
                                           .setVsyncPeriod(Fps(120.f).getPeriodNsecs())
                                           .setGroup(0)
                                           .build();

    scheduler::RefreshRateConfigs mConfigs{{mode60}, mode60->getId()};

    mock::SchedulerCallback mSchedulerCallback;

@@ -149,15 +158,14 @@ TEST_F(SchedulerTest, validConnectionHandle) {
    EXPECT_EQ(kEventConnections, mScheduler->getEventThreadConnectionCount(mConnectionHandle));
}

TEST_F(SchedulerTest, noLayerHistory) {
    // Layer history should not be created if there is a single config.
    ASSERT_FALSE(mScheduler->hasLayerHistory());

TEST_F(SchedulerTest, chooseRefreshRateForContentIsNoopWhenModeSwitchingIsNotSupported) {
    // The layer is registered at creation time and deregistered at destruction time.
    sp<mock::MockLayer> layer = sp<mock::MockLayer>::make(mFlinger.flinger());

    // Content detection should be no-op.
    mScheduler->registerLayer(layer.get());
    // recordLayerHistory should be a noop
    ASSERT_EQ(static_cast<size_t>(0), mScheduler->getNumActiveLayers());
    mScheduler->recordLayerHistory(layer.get(), 0, LayerHistory::LayerUpdateType::Buffer);
    ASSERT_EQ(static_cast<size_t>(0), mScheduler->getNumActiveLayers());

    constexpr bool kPowerStateNormal = true;
    mScheduler->setDisplayPowerState(kPowerStateNormal);
@@ -169,6 +177,18 @@ TEST_F(SchedulerTest, noLayerHistory) {
    mScheduler->chooseRefreshRateForContent();
}

TEST_F(SchedulerTest, updateDisplayModes) {
    ASSERT_EQ(static_cast<size_t>(0), mScheduler->layerHistorySize());
    sp<mock::MockLayer> layer = sp<mock::MockLayer>::make(mFlinger.flinger());
    ASSERT_EQ(static_cast<size_t>(1), mScheduler->layerHistorySize());

    mConfigs.updateDisplayModes({mode60, mode120}, /* activeMode */ mode60->getId());

    ASSERT_EQ(static_cast<size_t>(0), mScheduler->getNumActiveLayers());
    mScheduler->recordLayerHistory(layer.get(), 0, LayerHistory::LayerUpdateType::Buffer);
    ASSERT_EQ(static_cast<size_t>(1), mScheduler->getNumActiveLayers());
}

TEST_F(SchedulerTest, testDispatchCachedReportedMode) {
    // If the optional fields are cleared, the function should return before
    // onModeChange is called.
+5 −0
Original line number Diff line number Diff line
@@ -64,6 +64,11 @@ public:
        return mutableLayerHistory()->mLayerInfos.size();
    }

    size_t getNumActiveLayers() NO_THREAD_SAFETY_ANALYSIS {
        if (!mLayerHistory) return 0;
        return mutableLayerHistory()->mActiveLayersEnd;
    }

    void replaceTouchTimer(int64_t millis) {
        if (mTouchTimer) {
            mTouchTimer.reset();