SurfaceFlinger: define a known frame rates list

Keep a list of known frame rates that would be used when we calculated
heuristically the frame rate of a layer. This keeps the signal to the
algorithm that chooses the refresh rate steady and avoid strange
frame rates like 57.2 due to inconsistent presentation timestamps.

Bug: 157540021
Test: adb shell /data/nativetest64/libsurfaceflinger_unittest/libsurfaceflinger_unittest
Change-Id: I97a24b74605256646e9b8444bd9f3818fe0a4a2a
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
index f376b4a..2d3b01f 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
@@ -84,6 +84,22 @@
         return sp<mock::MockLayer>(new mock::MockLayer(mFlinger.flinger(), std::move(name)));
     }
 
+    void recordFramesAndExpect(const sp<mock::MockLayer>& layer, float frameRate,
+                               float desiredRefreshRate) {
+        nsecs_t time = systemTime();
+        const nsecs_t framePeriod = static_cast<nsecs_t>(1e9f / frameRate);
+
+        for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+            history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+            time += framePeriod;
+        }
+
+        ASSERT_EQ(1, history().summarize(time).size());
+        EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, history().summarize(time)[0].vote);
+        EXPECT_FLOAT_EQ(desiredRefreshRate, history().summarize(time)[0].desiredRefreshRate)
+                << "Frame rate is " << frameRate;
+    }
+
     Hwc2::mock::Display mDisplay;
     RefreshRateConfigs mConfigs{{HWC2::Display::Config::Builder(mDisplay, 0)
                                          .setVsyncPeriod(int32_t(LO_FPS_PERIOD))
@@ -600,6 +616,28 @@
     EXPECT_EQ(1, animatingLayerCount(time));
 }
 
+TEST_F(LayerHistoryTestV2, heuristicLayer60Hz) {
+    const auto layer = createLayer();
+    EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+    for (float fps = 54.0f; fps < 65.0f; fps += 0.1f) {
+        recordFramesAndExpect(layer, fps, 60.0f);
+    }
+}
+
+TEST_F(LayerHistoryTestV2, heuristicLayerNotOscillating) {
+    const auto layer = createLayer();
+    EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+    recordFramesAndExpect(layer, 27.10f, 30.0f);
+    recordFramesAndExpect(layer, 26.50f, 30.0f);
+    recordFramesAndExpect(layer, 25.90f, 24.0f);
+    recordFramesAndExpect(layer, 26.50f, 24.0f);
+    recordFramesAndExpect(layer, 27.10f, 30.0f);
+}
+
 class LayerHistoryTestV2Parameterized
       : public LayerHistoryTestV2,
         public testing::WithParamInterface<std::chrono::nanoseconds> {};
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index c919e93..4fa8455 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -43,6 +43,14 @@
     RefreshRateConfigsTest();
     ~RefreshRateConfigsTest();
 
+    float findClosestKnownFrameRate(const RefreshRateConfigs& refreshRateConfigs, float frameRate) {
+        return refreshRateConfigs.findClosestKnownFrameRate(frameRate);
+    }
+
+    std::vector<float> getKnownFrameRate(const RefreshRateConfigs& refreshRateConfigs) {
+        return refreshRateConfigs.mKnownFrameRates;
+    }
+
     // Test config IDs
     static inline const HwcConfigIndexType HWC_CONFIG_ID_60 = HwcConfigIndexType(0);
     static inline const HwcConfigIndexType HWC_CONFIG_ID_90 = HwcConfigIndexType(1);
@@ -902,8 +910,7 @@
         const auto& refreshRate =
                 refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
                                                        /*idle*/ false, &ignored);
-        printf("%.2fHz chooses %s\n", fps, refreshRate.getName().c_str());
-        EXPECT_EQ(mExpected60Config, refreshRate);
+        EXPECT_EQ(mExpected60Config, refreshRate) << fps << "Hz chooses " << refreshRate.getName();
     }
 }
 
@@ -989,8 +996,7 @@
         const auto& refreshRate =
                 refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
                                                        /*idle*/ false, &ignored);
-        printf("%.2fHz chooses %s\n", fps, refreshRate.getName().c_str());
-        EXPECT_EQ(mExpected90Config, refreshRate);
+        EXPECT_EQ(mExpected90Config, refreshRate) << fps << "Hz chooses " << refreshRate.getName();
     }
 }
 
@@ -1456,6 +1462,73 @@
                       .getConfigId());
 }
 
+TEST_F(RefreshRateConfigsTest, findClosestKnownFrameRate) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m60_90Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+    for (float fps = 1.0f; fps <= 120.0f; fps += 0.1f) {
+        const auto knownFrameRate = findClosestKnownFrameRate(*refreshRateConfigs, fps);
+        float expectedFrameRate;
+        if (fps < 26.91f) {
+            expectedFrameRate = 24.0f;
+        } else if (fps < 37.51f) {
+            expectedFrameRate = 30.0f;
+        } else if (fps < 52.51f) {
+            expectedFrameRate = 45.0f;
+        } else if (fps < 66.01f) {
+            expectedFrameRate = 60.0f;
+        } else if (fps < 81.01f) {
+            expectedFrameRate = 72.0f;
+        } else {
+            expectedFrameRate = 90.0f;
+        }
+        EXPECT_FLOAT_EQ(expectedFrameRate, knownFrameRate)
+                << "findClosestKnownFrameRate(" << fps << ") = " << knownFrameRate;
+    }
+}
+
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_KnownFrameRate) {
+    bool ignored;
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m60_90Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+    struct ExpectedRate {
+        float rate;
+        const RefreshRate& expected;
+    };
+
+    /* clang-format off */
+    std::vector<ExpectedRate> knownFrameRatesExpectations = {
+        {24.0f, mExpected60Config},
+        {30.0f, mExpected60Config},
+        {45.0f, mExpected90Config},
+        {60.0f, mExpected60Config},
+        {72.0f, mExpected90Config},
+        {90.0f, mExpected90Config},
+    };
+    /* clang-format on */
+
+    // Make sure the test tests all the known frame rate
+    const auto knownFrameRateList = getKnownFrameRate(*refreshRateConfigs);
+    const auto equal = std::equal(knownFrameRateList.begin(), knownFrameRateList.end(),
+                                  knownFrameRatesExpectations.begin(),
+                                  [](float a, const ExpectedRate& b) { return a == b.rate; });
+    EXPECT_TRUE(equal);
+
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    auto& layer = layers[0];
+    layer.vote = LayerVoteType::Heuristic;
+    for (const auto& expectedRate : knownFrameRatesExpectations) {
+        layer.desiredRefreshRate = expectedRate.rate;
+        const auto& refreshRate = refreshRateConfigs->getBestRefreshRate(layers,
+                                                                         /*touchActive*/ false,
+                                                                         /*idle*/ false, &ignored);
+        EXPECT_EQ(expectedRate.expected, refreshRate);
+    }
+}
+
 } // namespace
 } // namespace scheduler
 } // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index 41b5d49..d5ecae8 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -31,7 +31,7 @@
     TestableScheduler(const scheduler::RefreshRateConfigs& configs, bool useContentDetectionV2)
           : Scheduler([](bool) {}, configs, *this, useContentDetectionV2, true) {
         if (mUseContentDetectionV2) {
-            mLayerHistory = std::make_unique<scheduler::impl::LayerHistoryV2>();
+            mLayerHistory = std::make_unique<scheduler::impl::LayerHistoryV2>(configs);
         } else {
             mLayerHistory = std::make_unique<scheduler::impl::LayerHistory>();
         }
@@ -43,7 +43,7 @@
           : Scheduler(std::move(primaryDispSync), std::move(eventControlThread), configs, *this,
                       useContentDetectionV2, true) {
         if (mUseContentDetectionV2) {
-            mLayerHistory = std::make_unique<scheduler::impl::LayerHistoryV2>();
+            mLayerHistory = std::make_unique<scheduler::impl::LayerHistoryV2>(configs);
         } else {
             mLayerHistory = std::make_unique<scheduler::impl::LayerHistory>();
         }