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

Commit 21ce06ab authored by Ady Abraham's avatar Ady Abraham Committed by Automerger Merge Worker
Browse files

SF: give a higher score to frame rates which exact matches am: 03c02087

Original change: https://android-review.googlesource.com/c/platform/frameworks/native/+/1953899

Change-Id: I8fea473e5e06935598ddf4d81d0a95e398b038b4
parents 2d9f9037 03c02087
Loading
Loading
Loading
Loading
+39 −23
Original line number Diff line number Diff line
@@ -133,27 +133,10 @@ bool RefreshRateConfigs::isVoteAllowed(const LayerRequirement& layer,
    return true;
}

float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& layer,
                                                    const RefreshRate& refreshRate,
                                                    bool isSeamlessSwitch) const {
    if (!isVoteAllowed(layer, refreshRate)) {
        return 0;
    }

float RefreshRateConfigs::calculateNonExactMatchingLayerScoreLocked(
        const LayerRequirement& layer, const RefreshRate& refreshRate) const {
    constexpr float kScoreForFractionalPairs = .8f;

    // Slightly prefer seamless switches.
    constexpr float kSeamedSwitchPenalty = 0.95f;
    const float seamlessness = isSeamlessSwitch ? 1.0f : kSeamedSwitchPenalty;

    // If the layer wants Max, give higher score to the higher refresh rate
    if (layer.vote == LayerVoteType::Max) {
        const auto ratio =
                refreshRate.fps.getValue() / mAppRequestRefreshRates.back()->fps.getValue();
        // use ratio^2 to get a lower score the more we get further from peak
        return ratio * ratio;
    }

    const auto displayPeriod = refreshRate.getVsyncPeriod();
    const auto layerPeriod = layer.desiredRefreshRate.getPeriodNsecs();
    if (layer.vote == LayerVoteType::ExplicitDefault) {
@@ -178,7 +161,7 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye
    if (layer.vote == LayerVoteType::ExplicitExactOrMultiple ||
        layer.vote == LayerVoteType::Heuristic) {
        if (isFractionalPairOrMultiple(refreshRate.getFps(), layer.desiredRefreshRate)) {
            return kScoreForFractionalPairs * seamlessness;
            return kScoreForFractionalPairs;
        }

        // Calculate how many display vsyncs we need to present a single frame for this
@@ -188,7 +171,7 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye
        static constexpr size_t MAX_FRAMES_TO_FIT = 10; // Stop calculating when score < 0.1
        if (displayFramesRemainder == 0) {
            // Layer desired refresh rate matches the display rate.
            return 1.0f * seamlessness;
            return 1.0f;
        }

        if (displayFramesQuotient == 0) {
@@ -206,7 +189,29 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye
            iter++;
        }

        return (1.0f / iter) * seamlessness;
        return (1.0f / iter);
    }

    return 0;
}

float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& layer,
                                                    const RefreshRate& refreshRate,
                                                    bool isSeamlessSwitch) const {
    if (!isVoteAllowed(layer, refreshRate)) {
        return 0;
    }

    // Slightly prefer seamless switches.
    constexpr float kSeamedSwitchPenalty = 0.95f;
    const float seamlessness = isSeamlessSwitch ? 1.0f : kSeamedSwitchPenalty;

    // If the layer wants Max, give higher score to the higher refresh rate
    if (layer.vote == LayerVoteType::Max) {
        const auto ratio = refreshRate.getFps().getValue() /
                mAppRequestRefreshRates.back()->getFps().getValue();
        // use ratio^2 to get a lower score the more we get further from peak
        return ratio * ratio;
    }

    if (layer.vote == LayerVoteType::ExplicitExact) {
@@ -221,7 +226,18 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye
        return divider == 1;
    }

    return 0;
    // If the layer frame rate is a divider of the refresh rate it should score
    // the highest score.
    if (getFrameRateDivider(refreshRate.getFps(), layer.desiredRefreshRate) > 0) {
        return 1.0f * seamlessness;
    }

    // The layer frame rate is not a divider of the refresh rate,
    // there is a small penalty attached to the score to favor the frame rates
    // the exactly matches the display refresh rate or a multiple.
    constexpr float kNonExactMatchingPenalty = 0.99f;
    return calculateNonExactMatchingLayerScoreLocked(layer, refreshRate) * seamlessness *
            kNonExactMatchingPenalty;
}

struct RefreshRateScore {
+3 −0
Original line number Diff line number Diff line
@@ -409,6 +409,9 @@ private:
    float calculateLayerScoreLocked(const LayerRequirement&, const RefreshRate&,
                                    bool isSeamlessSwitch) const REQUIRES(mLock);

    float calculateNonExactMatchingLayerScoreLocked(const LayerRequirement&,
                                                    const RefreshRate&) const REQUIRES(mLock);

    // The list of refresh rates, indexed by display modes ID. This may change after this
    // object is initialized.
    AllRefreshRatesMapType mRefreshRates GUARDED_BY(mLock);
+38 −1
Original line number Diff line number Diff line
@@ -183,7 +183,6 @@ protected:
    RefreshRate mExpected120Config = {HWC_CONFIG_ID_120, mConfig120, Fps(120),
                                      RefreshRate::ConstructorTag(0)};

private:
    DisplayModePtr createDisplayMode(DisplayModeId modeId, int32_t group, int64_t vsyncPeriod,
                                     ui::Size resolution = ui::Size());
};
@@ -2177,6 +2176,44 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_FractionalRefreshRates_ExactAn
              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
}

// b/190578904
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_deviceWithCloseRefreshRates) {
    constexpr int kMinRefreshRate = 10;
    constexpr int kMaxRefreshRate = 240;

    DisplayModes displayModes;
    for (int fps = kMinRefreshRate; fps < kMaxRefreshRate; fps++) {
        constexpr int32_t kGroup = 0;
        const auto refreshRate = Fps(static_cast<float>(fps));
        displayModes.push_back(
                createDisplayMode(DisplayModeId(fps), kGroup, refreshRate.getPeriodNsecs()));
    }

    const RefreshRateConfigs::GlobalSignals globalSignals = {.touch = false, .idle = false};
    auto refreshRateConfigs =
            std::make_unique<RefreshRateConfigs>(displayModes,
                                                 /*currentConfigId=*/displayModes[0]->getId());

    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
    const auto testRefreshRate = [&](Fps fps, LayerVoteType vote) {
        layers[0].desiredRefreshRate = fps;
        layers[0].vote = vote;
        EXPECT_EQ(fps.getIntValue(),
                  refreshRateConfigs->getBestRefreshRate(layers, globalSignals)
                          .getFps()
                          .getIntValue())
                << "Failed for " << RefreshRateConfigs::layerVoteTypeString(vote);
    };

    for (int fps = kMinRefreshRate; fps < kMaxRefreshRate; fps++) {
        const auto refreshRate = Fps(static_cast<float>(fps));
        testRefreshRate(refreshRate, LayerVoteType::Heuristic);
        testRefreshRate(refreshRate, LayerVoteType::ExplicitDefault);
        testRefreshRate(refreshRate, LayerVoteType::ExplicitExactOrMultiple);
        testRefreshRate(refreshRate, LayerVoteType::ExplicitExact);
    }
}

TEST_F(RefreshRateConfigsTest, testComparisonOperator) {
    EXPECT_TRUE(mExpected60Config < mExpected90Config);
    EXPECT_FALSE(mExpected60Config < mExpected60Config);