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

Commit 513e6507 authored by ramindani's avatar ramindani Committed by Ram Indani
Browse files

[SF] Add a support for N VSyncs in FrameTargeter

Currently supports 5 past vsyncs

Test: atest FrameTargeterTest
BUG: 308858993
Flag: allow_n_vsyncs_in_targeter
Change-Id: Ie240fc5a65728496b7d20d35d14d7e05a0b77817
parent 8470d768
Loading
Loading
Loading
Loading
+23 −1
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@
// TODO(b/185536303): Pull to FTL.
#include "../../../TracedOrdinal.h"
#include "../../../Utils/Dumper.h"
#include "../../../Utils/RingBuffer.h"

namespace android::scheduler {

@@ -61,7 +62,7 @@ public:
    // VSYNC of at least one previous frame has not yet passed. In other words, this is NOT the
    // `presentFenceForPreviousFrame` if running N VSYNCs ahead, but the one that should have been
    // signaled by now (unless that frame missed).
    const FenceTimePtr& presentFenceForPastVsync(Period minFramePeriod) const;
    FenceTimePtr presentFenceForPastVsync(Period minFramePeriod) const;

    // Equivalent to `presentFenceForPastVsync` unless running N VSYNCs ahead.
    const FenceTimePtr& presentFenceForPreviousFrame() const {
@@ -84,6 +85,12 @@ protected:
        return mExpectedPresentTime - minFramePeriod;
    }

    void addFence(sp<Fence> presentFence, FenceTimePtr presentFenceTime,
                  TimePoint expectedPresentTime) {
        mFenceWithFenceTimes.next() = {std::move(presentFence), presentFenceTime,
                                       expectedPresentTime};
    }

    VsyncId mVsyncId;
    TimePoint mFrameBeginTime;
    TimePoint mExpectedPresentTime;
@@ -97,8 +104,11 @@ protected:
    struct FenceWithFenceTime {
        sp<Fence> fence = Fence::NO_FENCE;
        FenceTimePtr fenceTime = FenceTime::NO_FENCE;
        TimePoint expectedPresentTime = TimePoint();
    };
    std::array<FenceWithFenceTime, 2> mPresentFences;
    utils::RingBuffer<FenceWithFenceTime, 5> mFenceWithFenceTimes;

    TimePoint mLastSignaledFrameTime;

private:
@@ -109,6 +119,18 @@ private:
        static_assert(N > 1);
        return expectedFrameDuration() > (N - 1) * minFramePeriod;
    }

    const FenceTimePtr pastVsyncTimePtr() const {
        auto pastFenceTimePtr = FenceTime::NO_FENCE;
        for (size_t i = 0; i < mFenceWithFenceTimes.size(); i++) {
            const auto& [_, fenceTimePtr, expectedPresentTime] = mFenceWithFenceTimes[i];
            if (expectedPresentTime > mFrameBeginTime) {
                return pastFenceTimePtr;
            }
            pastFenceTimePtr = fenceTimePtr;
        }
        return pastFenceTimePtr;
    }
};

// Computes a display's per-frame metrics about past/upcoming targeting of present deadlines.
+13 −5
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

#include <gui/TraceUtils.h>

#include <common/FlagManager.h>
#include <scheduler/FrameTargeter.h>
#include <scheduler/IVsyncSource.h>

@@ -33,8 +34,10 @@ TimePoint FrameTarget::pastVsyncTime(Period minFramePeriod) const {
    return mExpectedPresentTime - Period::fromNs(minFramePeriod.ns() << shift);
}

const FenceTimePtr& FrameTarget::presentFenceForPastVsync(Period minFramePeriod) const {
    // TODO(b/267315508): Generalize to N VSYNCs.
FenceTimePtr FrameTarget::presentFenceForPastVsync(Period minFramePeriod) const {
    if (FlagManager::getInstance().allow_n_vsyncs_in_targeter()) {
        return pastVsyncTimePtr();
    }
    const size_t i = static_cast<size_t>(targetsVsyncsAhead<2>(minFramePeriod));
    return mPresentFences[i].fenceTime;
}
@@ -44,7 +47,8 @@ bool FrameTarget::wouldPresentEarly(Period minFramePeriod) const {
    // should use `TimePoint::now()` in case of delays since `mFrameBeginTime`.

    // TODO(b/267315508): Generalize to N VSYNCs.
    if (targetsVsyncsAhead<3>(minFramePeriod)) {
    const bool allowNVsyncs = FlagManager::getInstance().allow_n_vsyncs_in_targeter();
    if (!allowNVsyncs && targetsVsyncsAhead<3>(minFramePeriod)) {
        return true;
    }

@@ -144,8 +148,12 @@ FenceTimePtr FrameTargeter::setPresentFence(sp<Fence> presentFence) {
}

FenceTimePtr FrameTargeter::setPresentFence(sp<Fence> presentFence, FenceTimePtr presentFenceTime) {
    if (FlagManager::getInstance().allow_n_vsyncs_in_targeter()) {
        addFence(std::move(presentFence), presentFenceTime, mExpectedPresentTime);
    } else {
        mPresentFences[1] = mPresentFences[0];
    mPresentFences[0] = {std::move(presentFence), presentFenceTime};
        mPresentFences[0] = {std::move(presentFence), presentFenceTime, mExpectedPresentTime};
    }
    return presentFenceTime;
}

+103 −1
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@

#include <com_android_graphics_surfaceflinger_flags.h>

using namespace com::android::graphics::surfaceflinger;
using namespace std::chrono_literals;

namespace android::scheduler {
@@ -168,6 +169,7 @@ TEST_F(FrameTargeterTest, inflatesExpectedPresentTime) {
}

TEST_F(FrameTargeterTest, recallsPastVsync) {
    SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);
    VsyncId vsyncId{111};
    TimePoint frameBeginTime(1000ms);
    constexpr Fps kRefreshRate = 60_Hz;
@@ -184,6 +186,7 @@ TEST_F(FrameTargeterTest, recallsPastVsync) {
}

TEST_F(FrameTargeterTest, recallsPastVsyncTwoVsyncsAhead) {
    SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);
    VsyncId vsyncId{222};
    TimePoint frameBeginTime(2000ms);
    constexpr Fps kRefreshRate = 120_Hz;
@@ -203,8 +206,32 @@ TEST_F(FrameTargeterTest, recallsPastVsyncTwoVsyncsAhead) {
    }
}

TEST_F(FrameTargeterTest, recallsPastNVsyncTwoVsyncsAhead) {
    SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, true);
    VsyncId vsyncId{222};
    TimePoint frameBeginTime(2000ms);
    constexpr Fps kRefreshRate = 120_Hz;
    constexpr Period kPeriod = kRefreshRate.getPeriod();
    constexpr Duration kFrameDuration = 10ms;

    FenceTimePtr previousFence = FenceTime::NO_FENCE;

    for (int n = 5; n-- > 0;) {
        Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate);
        const auto fence = frame.end();

        const auto pastVsyncTime = frameBeginTime + kFrameDuration - 2 * kPeriod;
        EXPECT_EQ(target().pastVsyncTime(kPeriod), pastVsyncTime);
        EXPECT_EQ(target().presentFenceForPastVsync(kFrameDuration), previousFence);

        frameBeginTime += kPeriod;
        previousFence = fence;
    }
}

TEST_F(FrameTargeterTest, recallsPastVsyncTwoVsyncsAheadVrr) {
    SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::vrr_config, true);
    SET_FLAG_FOR_TEST(flags::vrr_config, true);
    SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);

    VsyncId vsyncId{222};
    TimePoint frameBeginTime(2000ms);
@@ -227,6 +254,33 @@ TEST_F(FrameTargeterTest, recallsPastVsyncTwoVsyncsAheadVrr) {
    }
}

TEST_F(FrameTargeterTest, recallsPastNVsyncTwoVsyncsAheadVrr) {
    SET_FLAG_FOR_TEST(flags::vrr_config, true);
    SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, true);

    VsyncId vsyncId{222};
    TimePoint frameBeginTime(2000ms);
    constexpr Fps kRefreshRate = 120_Hz;
    constexpr Fps kPeakRefreshRate = 240_Hz;
    constexpr Period kPeriod = kRefreshRate.getPeriod();
    constexpr Duration kFrameDuration = 10ms;

    FenceTimePtr previousFence = FenceTime::NO_FENCE;

    for (int n = 5; n-- > 0;) {
        Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate,
                    kPeakRefreshRate);
        const auto fence = frame.end();

        const auto pastVsyncTime = frameBeginTime + kFrameDuration - 2 * kPeriod;
        EXPECT_EQ(target().pastVsyncTime(kPeriod), pastVsyncTime);
        EXPECT_EQ(target().presentFenceForPastVsync(kFrameDuration), previousFence);

        frameBeginTime += kPeriod;
        previousFence = fence;
    }
}

TEST_F(FrameTargeterTest, doesNotDetectEarlyPresentIfNoFence) {
    constexpr Period kPeriod = (60_Hz).getPeriod();
    EXPECT_EQ(target().presentFenceForPastVsync(kPeriod), FenceTime::NO_FENCE);
@@ -234,6 +288,7 @@ TEST_F(FrameTargeterTest, doesNotDetectEarlyPresentIfNoFence) {
}

TEST_F(FrameTargeterTest, detectsEarlyPresent) {
    SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);
    VsyncId vsyncId{333};
    TimePoint frameBeginTime(3000ms);
    constexpr Fps kRefreshRate = 60_Hz;
@@ -263,6 +318,7 @@ TEST_F(FrameTargeterTest, detectsEarlyPresent) {
// Same as `detectsEarlyPresent`, above, but verifies that we do not set an earliest present time
// when there is expected present time support.
TEST_F(FrameTargeterWithExpectedPresentSupportTest, detectsEarlyPresent) {
    SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);
    VsyncId vsyncId{333};
    TimePoint frameBeginTime(3000ms);
    constexpr Fps kRefreshRate = 60_Hz;
@@ -289,6 +345,7 @@ TEST_F(FrameTargeterWithExpectedPresentSupportTest, detectsEarlyPresent) {
}

TEST_F(FrameTargeterTest, detectsEarlyPresentTwoVsyncsAhead) {
    SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);
    VsyncId vsyncId{444};
    TimePoint frameBeginTime(4000ms);
    constexpr Fps kRefreshRate = 120_Hz;
@@ -320,7 +377,52 @@ TEST_F(FrameTargeterTest, detectsEarlyPresentTwoVsyncsAhead) {
              target().expectedPresentTime() - kPeriod - kHwcMinWorkDuration);
}

TEST_F(FrameTargeterTest, detectsEarlyPresentNVsyncsAhead) {
    SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, true);
    VsyncId vsyncId{444};
    TimePoint frameBeginTime(4000ms);
    Fps refreshRate = 120_Hz;
    Period period = refreshRate.getPeriod();

    // The target is not early while past present fences are pending.
    for (int n = 5; n-- > 0;) {
        const Frame frame(this, vsyncId++, frameBeginTime, 10ms, refreshRate, refreshRate);
        EXPECT_FALSE(wouldPresentEarly(period));
        EXPECT_FALSE(target().earliestPresentTime());
    }

    Frame frame(this, vsyncId++, frameBeginTime, 10ms, refreshRate, refreshRate);
    auto fence = frame.end();
    frameBeginTime += period;
    fence->signalForTest(frameBeginTime.ns());

    // The target is two VSYNCs ahead, so the past present fence is still pending.
    EXPECT_FALSE(wouldPresentEarly(period));
    EXPECT_FALSE(target().earliestPresentTime());

    { const Frame frame(this, vsyncId++, frameBeginTime, 10ms, refreshRate, refreshRate); }

    Frame oneEarlyPresentFrame(this, vsyncId++, frameBeginTime, 10ms, refreshRate, refreshRate);
    // The target is early if the past present fence was signaled.
    EXPECT_TRUE(wouldPresentEarly(period));
    ASSERT_NE(std::nullopt, target().earliestPresentTime());
    EXPECT_EQ(*target().earliestPresentTime(),
              target().expectedPresentTime() - period - kHwcMinWorkDuration);

    fence = oneEarlyPresentFrame.end();
    frameBeginTime += period;
    fence->signalForTest(frameBeginTime.ns());

    // Change rate to track frame more than 2 vsyncs ahead
    refreshRate = 144_Hz;
    period = refreshRate.getPeriod();
    Frame onePresentEarlyFrame(this, vsyncId++, frameBeginTime, 16ms, refreshRate, refreshRate);
    // The target is not early as last frame as the past frame is tracked for pending.
    EXPECT_FALSE(wouldPresentEarly(period));
}

TEST_F(FrameTargeterTest, detectsEarlyPresentThreeVsyncsAhead) {
    SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);
    TimePoint frameBeginTime(5000ms);
    constexpr Fps kRefreshRate = 144_Hz;
    constexpr Period kPeriod = kRefreshRate.getPeriod();