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

Commit aa3f2850 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "SurfaceFlinger: add a test for unknown offset" into rvc-dev am: 8d8ff36e

Change-Id: I645a2039896ff8f232956896b00822986e0a6b4a
parents 65dbfd20 8d8ff36e
Loading
Loading
Loading
Loading
+32 −25
Original line number Diff line number Diff line
@@ -36,6 +36,19 @@ bool fpsEqualsWithMargin(float fpsA, float fpsB) {
    return std::abs(fpsA - fpsB) <= MARGIN;
}

std::vector<float> getRefreshRatesFromConfigs(
        const android::scheduler::RefreshRateConfigs& refreshRateConfigs) {
    const auto& allRefreshRates = refreshRateConfigs.getAllRefreshRates();
    std::vector<float> refreshRates;
    refreshRates.reserve(allRefreshRates.size());

    for (const auto& [ignored, refreshRate] : allRefreshRates) {
        refreshRates.emplace_back(refreshRate->fps);
    }

    return refreshRates;
}

} // namespace

namespace android::scheduler {
@@ -45,14 +58,21 @@ PhaseConfiguration::~PhaseConfiguration() = default;
namespace impl {

PhaseOffsets::PhaseOffsets(const scheduler::RefreshRateConfigs& refreshRateConfigs)
      : // Below defines the threshold when an offset is considered to be negative, i.e. targeting
        // for the N+2 vsync instead of N+1. This means that:
        // For offset < threshold, SF wake up (vsync_duration - offset) before HW vsync.
        // For offset >= threshold, SF wake up (2 * vsync_duration - offset) before HW vsync.
        mThresholdForNextVsync(getProperty("debug.sf.phase_offset_threshold_for_next_vsync_ns")
                                       .value_or(std::numeric_limits<nsecs_t>::max())),
        mOffsets(initializeOffsets(refreshRateConfigs)),
        mRefreshRateFps(refreshRateConfigs.getCurrentRefreshRate().fps) {}
      : PhaseOffsets(getRefreshRatesFromConfigs(refreshRateConfigs),
                     refreshRateConfigs.getCurrentRefreshRate().fps,
                     // Below defines the threshold when an offset is considered to be negative,
                     // i.e. targeting for the N+2 vsync instead of N+1. This means that: For offset
                     // < threshold, SF wake up (vsync_duration - offset) before HW vsync. For
                     // offset >= threshold, SF wake up (2 * vsync_duration - offset) before HW
                     // vsync.
                     getProperty("debug.sf.phase_offset_threshold_for_next_vsync_ns")
                             .value_or(std::numeric_limits<nsecs_t>::max())) {}

PhaseOffsets::PhaseOffsets(const std::vector<float>& refreshRates, float currentFps,
                           nsecs_t thresholdForNextVsync)
      : mThresholdForNextVsync(thresholdForNextVsync),
        mOffsets(initializeOffsets(refreshRates)),
        mRefreshRateFps(currentFps) {}

void PhaseOffsets::dump(std::string& result) const {
    const auto [early, earlyGl, late] = getCurrentOffsets();
@@ -67,12 +87,12 @@ void PhaseOffsets::dump(std::string& result) const {
}

std::unordered_map<float, PhaseOffsets::Offsets> PhaseOffsets::initializeOffsets(
        const scheduler::RefreshRateConfigs& refreshRateConfigs) const {
        const std::vector<float>& refreshRates) const {
    std::unordered_map<float, Offsets> offsets;

    for (const auto& [ignored, refreshRate] : refreshRateConfigs.getAllRefreshRates()) {
        const float fps = refreshRate->fps;
        offsets.emplace(fps, getPhaseOffsets(fps, refreshRate->vsyncPeriod));
    for (const auto& refreshRate : refreshRates) {
        offsets.emplace(refreshRate,
                        getPhaseOffsets(refreshRate, static_cast<nsecs_t>(1e9f / refreshRate)));
    }
    return offsets;
}
@@ -243,19 +263,6 @@ PhaseDurations::Offsets PhaseDurations::constructOffsets(nsecs_t vsyncDuration)
    };
}

static std::vector<float> getRefreshRatesFromConfigs(
        const android::scheduler::RefreshRateConfigs& refreshRateConfigs) {
    const auto& allRefreshRates = refreshRateConfigs.getAllRefreshRates();
    std::vector<float> refreshRates;
    refreshRates.reserve(allRefreshRates.size());

    for (const auto& [ignored, refreshRate] : allRefreshRates) {
        refreshRates.emplace_back(refreshRate->fps);
    }

    return refreshRates;
}

std::unordered_map<float, PhaseDurations::Offsets> PhaseDurations::initializeOffsets(
        const std::vector<float>& refreshRates) const {
    std::unordered_map<float, Offsets> offsets;
+5 −2
Original line number Diff line number Diff line
@@ -66,9 +66,12 @@ public:
    // Returns current offsets in human friendly format.
    void dump(std::string& result) const override;

private:
protected:
    // Used for unit tests
    PhaseOffsets(const std::vector<float>& refreshRates, float currentFps,
                 nsecs_t thresholdForNextVsync);
    std::unordered_map<float, Offsets> initializeOffsets(
            const scheduler::RefreshRateConfigs&) const;
            const std::vector<float>& refreshRates) const;
    Offsets getDefaultOffsets(nsecs_t vsyncPeriod) const;
    Offsets getHighFpsOffsets(nsecs_t vsyncPeriod) const;
    Offsets getPhaseOffsets(float fps, nsecs_t vsyncPeriod) const;
+63 −15
Original line number Diff line number Diff line
@@ -42,25 +42,25 @@ public:
                                 appEarlyGlDuration) {}
};

class PhaseOffsetsTest : public testing::Test {
class PhaseDurationTest : public testing::Test {
protected:
    PhaseOffsetsTest()
          : mPhaseOffsets(60.0f, 10'500'000, 20'500'000, 16'000'000, 33'500'000, 13'500'000,
    PhaseDurationTest()
          : mPhaseDurations(60.0f, 10'500'000, 20'500'000, 16'000'000, 33'500'000, 13'500'000,
                            38'000'000) {}

    ~PhaseOffsetsTest() = default;
    ~PhaseDurationTest() = default;

    TestablePhaseOffsetsAsDurations mPhaseOffsets;
    TestablePhaseOffsetsAsDurations mPhaseDurations;
};

namespace {
/* ------------------------------------------------------------------------
 * Test cases
 */
TEST_F(PhaseOffsetsTest, getOffsetsForRefreshRate_60Hz) {
    mPhaseOffsets.setRefreshRateFps(60.0f);
    auto currentOffsets = mPhaseOffsets.getCurrentOffsets();
    auto offsets = mPhaseOffsets.getOffsetsForRefreshRate(60.0f);
TEST_F(PhaseDurationTest, getOffsetsForRefreshRate_60Hz) {
    mPhaseDurations.setRefreshRateFps(60.0f);
    auto currentOffsets = mPhaseDurations.getCurrentOffsets();
    auto offsets = mPhaseDurations.getOffsetsForRefreshRate(60.0f);

    EXPECT_EQ(currentOffsets, offsets);
    EXPECT_EQ(offsets.late.sf, 6'166'667);
@@ -76,10 +76,10 @@ TEST_F(PhaseOffsetsTest, getOffsetsForRefreshRate_60Hz) {
    EXPECT_EQ(offsets.earlyGl.app, 15'166'668);
}

TEST_F(PhaseOffsetsTest, getOffsetsForRefreshRate_90Hz) {
    mPhaseOffsets.setRefreshRateFps(90.0f);
    auto currentOffsets = mPhaseOffsets.getCurrentOffsets();
    auto offsets = mPhaseOffsets.getOffsetsForRefreshRate(90.0f);
TEST_F(PhaseDurationTest, getOffsetsForRefreshRate_90Hz) {
    mPhaseDurations.setRefreshRateFps(90.0f);
    auto currentOffsets = mPhaseDurations.getCurrentOffsets();
    auto offsets = mPhaseDurations.getOffsetsForRefreshRate(90.0f);

    EXPECT_EQ(currentOffsets, offsets);
    EXPECT_EQ(offsets.late.sf, 611'111);
@@ -95,7 +95,7 @@ TEST_F(PhaseOffsetsTest, getOffsetsForRefreshRate_90Hz) {
    EXPECT_EQ(offsets.earlyGl.app, 4'055'555);
}

TEST_F(PhaseOffsetsTest, getOffsetsForRefreshRate_DefaultOffsets) {
TEST_F(PhaseDurationTest, getOffsetsForRefreshRate_DefaultOffsets) {
    TestablePhaseOffsetsAsDurations phaseOffsetsWithDefaultValues(60.0f, -1, -1, -1, -1, -1, -1);

    auto validateOffsets = [](auto& offsets) {
@@ -125,6 +125,54 @@ TEST_F(PhaseOffsetsTest, getOffsetsForRefreshRate_DefaultOffsets) {
    validateOffsets(offsets);
}

TEST_F(PhaseDurationTest, getOffsetsForRefreshRate_unknownRefreshRate) {
    auto offsets = mPhaseDurations.getOffsetsForRefreshRate(14.7f);

    EXPECT_EQ(offsets.late.sf, 57'527'208);

    EXPECT_EQ(offsets.late.app, 37'027'208);

    EXPECT_EQ(offsets.early.sf, 52'027'208);

    EXPECT_EQ(offsets.early.app, 18'527'208);

    EXPECT_EQ(offsets.earlyGl.sf, 54'527'208);

    EXPECT_EQ(offsets.earlyGl.app, 16'527'208);
}

} // namespace

class TestablePhaseOffsets : public impl::PhaseOffsets {
public:
    TestablePhaseOffsets() : impl::PhaseOffsets({60.0f, 90.0f}, 60.0f, 10'000'000) {}
};

class PhaseOffsetsTest : public testing::Test {
protected:
    PhaseOffsetsTest() = default;
    ~PhaseOffsetsTest() = default;

    TestablePhaseOffsets mPhaseOffsets;
};

namespace {
TEST_F(PhaseOffsetsTest, getOffsetsForRefreshRate_unknownRefreshRate) {
    auto offsets = mPhaseOffsets.getOffsetsForRefreshRate(14.7f);

    EXPECT_EQ(offsets.late.sf, 1'000'000);

    EXPECT_EQ(offsets.late.app, 1'000'000);

    EXPECT_EQ(offsets.early.sf, 1'000'000);

    EXPECT_EQ(offsets.early.app, 1'000'000);

    EXPECT_EQ(offsets.earlyGl.sf, 1'000'000);

    EXPECT_EQ(offsets.earlyGl.app, 1'000'000);
}

} // namespace
} // namespace scheduler
} // namespace android