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

Commit 465d99f7 authored by Dominik Laskowski's avatar Dominik Laskowski Committed by Android (Google) Code Review
Browse files

Merge changes I355dea76,I63d21c22

* changes:
  SF: Simplify per-display refresh rate selection
  SF: Deduplicate FakeDisplayInjector
parents ec87f532 01602522
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#pragma once

#include <ftl/small_map.h>
#include <ftl/small_vector.h>

namespace android::display {

@@ -28,4 +29,7 @@ using DisplayMap = ftl::SmallMap<Key, Value, 5>;
template <typename Key, typename Value>
using PhysicalDisplayMap = ftl::SmallMap<Key, Value, 3>;

template <typename T>
using PhysicalDisplayVector = ftl::SmallVector<T, 3>;

} // namespace android::display
+75 −77
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
#include <configstore/Utils.h>
#include <ftl/fake_guard.h>
#include <ftl/small_map.h>
#include <gui/WindowInfo.h>
#include <system/window.h>
#include <utils/Timers.h>
@@ -41,6 +42,7 @@

#include "../Layer.h"
#include "DispSyncSource.h"
#include "Display/DisplayMap.h"
#include "EventThread.h"
#include "FrameRateOverrideMappings.h"
#include "OneShotTimer.h"
@@ -56,39 +58,6 @@
        }                                                            \
    } while (false)

namespace {

using android::Fps;
using android::FpsApproxEqual;
using android::FpsHash;
using android::scheduler::AggregatedFpsScore;
using android::scheduler::RefreshRateRankingsAndSignals;

// Returns the aggregated score per Fps for the RefreshRateRankingsAndSignals sourced.
auto getAggregatedScoresPerFps(
        const std::vector<RefreshRateRankingsAndSignals>& refreshRateRankingsAndSignalsPerDisplay)
        -> std::unordered_map<Fps, AggregatedFpsScore, FpsHash, FpsApproxEqual> {
    std::unordered_map<Fps, AggregatedFpsScore, FpsHash, FpsApproxEqual> aggregatedScoresPerFps;

    for (const auto& refreshRateRankingsAndSignal : refreshRateRankingsAndSignalsPerDisplay) {
        const auto& refreshRateRankings = refreshRateRankingsAndSignal.refreshRateRankings;

        std::for_each(refreshRateRankings.begin(), refreshRateRankings.end(), [&](const auto& it) {
            const auto [score, result] =
                    aggregatedScoresPerFps.try_emplace(it.displayModePtr->getFps(),
                                                       AggregatedFpsScore{it.score,
                                                                          /* numDisplays */ 1});
            if (!result) { // update
                score->second.totalScore += it.score;
                score->second.numDisplays++;
            }
        });
    }
    return aggregatedScoresPerFps;
}

} // namespace

namespace android::scheduler {

Scheduler::Scheduler(ICompositor& compositor, ISchedulerCallback& callback, FeatureFlags features)
@@ -157,6 +126,15 @@ void Scheduler::setRefreshRateConfigs(std::shared_ptr<RefreshRateConfigs> config
    mRefreshRateConfigs->startIdleTimer();
}

void Scheduler::registerDisplay(sp<const DisplayDevice> display) {
    const bool ok = mDisplays.try_emplace(display->getPhysicalId(), std::move(display)).second;
    ALOGE_IF(!ok, "%s: Duplicate display", __func__);
}

void Scheduler::unregisterDisplay(PhysicalDisplayId displayId) {
    mDisplays.erase(displayId);
}

void Scheduler::run() {
    while (true) {
        waitMessage();
@@ -711,66 +689,86 @@ auto Scheduler::applyPolicy(S Policy::*statePtr, T&& newState) -> GlobalSignals
    return consideredSignals;
}

void Scheduler::registerDisplay(const sp<const DisplayDevice>& display) {
    const bool ok = mDisplays.try_emplace(display->getPhysicalId(), display).second;
    ALOGE_IF(!ok, "Duplicate display registered");
}

void Scheduler::unregisterDisplay(PhysicalDisplayId displayId) {
    mDisplays.erase(displayId);
}

std::vector<DisplayModeConfig> Scheduler::getBestDisplayModeConfigs() const {
    ATRACE_CALL();

    std::vector<RefreshRateRankingsAndSignals> refreshRateRankingsAndSignalsPerDisplay;
    refreshRateRankingsAndSignalsPerDisplay.reserve(mDisplays.size());
    using Rankings = std::pair<std::vector<RefreshRateRanking>, GlobalSignals>;
    display::PhysicalDisplayVector<Rankings> perDisplayRankings;

    // Tallies the score of a refresh rate across `displayCount` displays.
    struct RefreshRateTally {
        explicit RefreshRateTally(float score) : score(score) {}

        float score;
        size_t displayCount = 1;
    };

    // Chosen to exceed a typical number of refresh rates across displays.
    constexpr size_t kStaticCapacity = 8;
    ftl::SmallMap<Fps, RefreshRateTally, kStaticCapacity, FpsApproxEqual> refreshRateTallies;

    const auto globalSignals = makeGlobalSignals();

    for (const auto& [id, display] : mDisplays) {
        const auto [rankings, signals] =
        auto [rankings, signals] =
                display->holdRefreshRateConfigs()
                        ->getRankedRefreshRates(mPolicy.contentRequirements, makeGlobalSignals());
                        ->getRankedRefreshRates(mPolicy.contentRequirements, globalSignals);

        for (const auto& [modePtr, score] : rankings) {
            const auto [it, inserted] = refreshRateTallies.try_emplace(modePtr->getFps(), score);

            if (!inserted) {
                auto& tally = it->second;
                tally.score += score;
                tally.displayCount++;
            }
        }

        refreshRateRankingsAndSignalsPerDisplay.emplace_back(
                RefreshRateRankingsAndSignals{rankings, signals});
        perDisplayRankings.emplace_back(std::move(rankings), signals);
    }

    // FPS and their Aggregated score.
    std::unordered_map<Fps, AggregatedFpsScore, FpsHash, FpsApproxEqual> aggregatedScoresPerFps =
            getAggregatedScoresPerFps(refreshRateRankingsAndSignalsPerDisplay);
    auto maxScoreIt = refreshRateTallies.cbegin();

    auto maxScoreIt = aggregatedScoresPerFps.cbegin();
    // Selects the max Fps that is present on all the displays.
    for (auto it = aggregatedScoresPerFps.cbegin(); it != aggregatedScoresPerFps.cend(); ++it) {
        const auto [fps, aggregatedScore] = *it;
        if (aggregatedScore.numDisplays == mDisplays.size() &&
            aggregatedScore.totalScore >= maxScoreIt->second.totalScore) {
    // Find the first refresh rate common to all displays.
    while (maxScoreIt != refreshRateTallies.cend() &&
           maxScoreIt->second.displayCount != mDisplays.size()) {
        ++maxScoreIt;
    }

    if (maxScoreIt != refreshRateTallies.cend()) {
        // Choose the highest refresh rate common to all displays, if any.
        for (auto it = maxScoreIt + 1; it != refreshRateTallies.cend(); ++it) {
            const auto [fps, tally] = *it;

            if (tally.displayCount == mDisplays.size() && tally.score > maxScoreIt->second.score) {
                maxScoreIt = it;
            }
        }
    return getDisplayModeConfigsForTheChosenFps(maxScoreIt->first,
                                                refreshRateRankingsAndSignalsPerDisplay);
    }

std::vector<DisplayModeConfig> Scheduler::getDisplayModeConfigsForTheChosenFps(
        Fps chosenFps,
        const std::vector<RefreshRateRankingsAndSignals>& refreshRateRankingsAndSignalsPerDisplay)
        const {
    const std::optional<Fps> chosenFps = maxScoreIt != refreshRateTallies.cend()
            ? std::make_optional(maxScoreIt->first)
            : std::nullopt;

    std::vector<DisplayModeConfig> displayModeConfigs;
    displayModeConfigs.reserve(mDisplays.size());

    using fps_approx_ops::operator==;
    std::for_each(refreshRateRankingsAndSignalsPerDisplay.begin(),
                  refreshRateRankingsAndSignalsPerDisplay.end(),
                  [&](const auto& refreshRateRankingsAndSignal) {
                      for (const auto& ranking : refreshRateRankingsAndSignal.refreshRateRankings) {
                          if (ranking.displayModePtr->getFps() == chosenFps) {
                              displayModeConfigs.emplace_back(
                                      DisplayModeConfig{refreshRateRankingsAndSignal.globalSignals,
                                                        ranking.displayModePtr});

    for (const auto& [rankings, signals] : perDisplayRankings) {
        if (!chosenFps) {
            displayModeConfigs.emplace_back(signals, rankings.front().displayModePtr);
            continue;
        }

        for (const auto& ranking : rankings) {
            const auto& modePtr = ranking.displayModePtr;
            if (modePtr->getFps() == *chosenFps) {
                displayModeConfigs.emplace_back(signals, modePtr);
                break;
            }
        }
                  });
    }
    return displayModeConfigs;
}

+6 −24
Original line number Diff line number Diff line
@@ -33,11 +33,12 @@
#include <ui/GraphicTypes.h>
#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"

#include <DisplayDevice.h>
#include <scheduler/Features.h>
#include <scheduler/Time.h>
#include <ui/DisplayId.h>

#include "Display/DisplayMap.h"
#include "DisplayDevice.h"
#include "EventThread.h"
#include "FrameRateOverrideMappings.h"
#include "LayerHistory.h"
@@ -108,19 +109,6 @@ protected:
    ~ISchedulerCallback() = default;
};

// Holds the total score of the FPS and
// number of displays the FPS is found in.
struct AggregatedFpsScore {
    float totalScore;
    size_t numDisplays;
};

// Represents the RefreshRateRankings and GlobalSignals for the selected RefreshRateRankings.
struct RefreshRateRankingsAndSignals {
    std::vector<RefreshRateRanking> refreshRateRankings;
    GlobalSignals globalSignals;
};

class Scheduler : android::impl::MessageQueue {
    using Impl = android::impl::MessageQueue;

@@ -132,6 +120,9 @@ public:
    void setRefreshRateConfigs(std::shared_ptr<RefreshRateConfigs>)
            EXCLUDES(mRefreshRateConfigsLock);

    void registerDisplay(sp<const DisplayDevice>);
    void unregisterDisplay(PhysicalDisplayId);

    void run();

    void createVsyncSchedule(FeatureFlags);
@@ -257,9 +248,6 @@ public:
        return mLayerHistory.getLayerFramerate(now, id);
    }

    void registerDisplay(const sp<const DisplayDevice>&);
    void unregisterDisplay(PhysicalDisplayId);

private:
    friend class TestableScheduler;

@@ -293,10 +281,6 @@ private:
    // Returns the best display mode per display.
    std::vector<DisplayModeConfig> getBestDisplayModeConfigs() const REQUIRES(mPolicyLock);

    // Returns the list of DisplayModeConfigs per display for the chosenFps.
    std::vector<DisplayModeConfig> getDisplayModeConfigsForTheChosenFps(
            Fps chosenFps, const std::vector<RefreshRateRankingsAndSignals>&) const;

    GlobalSignals makeGlobalSignals() const REQUIRES(mPolicyLock);

    bool updateFrameRateOverrides(GlobalSignals, Fps displayRefreshRate) REQUIRES(mPolicyLock);
@@ -344,9 +328,7 @@ private:

    mutable std::mutex mPolicyLock;

    // Holds the Physical displays registered through the SurfaceFlinger, used for making
    // the refresh rate selections.
    display::PhysicalDisplayMap<PhysicalDisplayId, const sp<const DisplayDevice>> mDisplays;
    display::PhysicalDisplayMap<PhysicalDisplayId, sp<const DisplayDevice>> mDisplays;

    struct Policy {
        // Policy for choosing the display mode.
+0 −4
Original line number Diff line number Diff line
@@ -138,10 +138,6 @@ struct FpsApproxEqual {
    bool operator()(Fps lhs, Fps rhs) const { return isApproxEqual(lhs, rhs); }
};

struct FpsHash {
    size_t operator()(Fps fps) const { return std::hash<nsecs_t>()(fps.getPeriodNsecs()); }
};

inline std::string to_string(Fps fps) {
    return base::StringPrintf("%.2f Hz", fps.getValue());
}
+0 −45
Original line number Diff line number Diff line
@@ -120,51 +120,6 @@ void DisplayTransactionTest::injectFakeNativeWindowSurfaceFactory() {
    });
}

sp<DisplayDevice> DisplayTransactionTest::injectDefaultInternalDisplay(
        std::function<void(FakeDisplayDeviceInjector&)> injectExtra) {
    constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(255u);
    constexpr int DEFAULT_DISPLAY_WIDTH = 1080;
    constexpr int DEFAULT_DISPLAY_HEIGHT = 1920;
    constexpr HWDisplayId DEFAULT_DISPLAY_HWC_DISPLAY_ID = 0;

    // The DisplayDevice is required to have a framebuffer (behind the
    // ANativeWindow interface) which uses the actual hardware display
    // size.
    EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
            .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_WIDTH), Return(0)));
    EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
            .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_HEIGHT), Return(0)));
    EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT));
    EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT));
    EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64));
    EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)).Times(AnyNumber());

    auto compositionDisplay =
            compositionengine::impl::createDisplay(mFlinger.getCompositionEngine(),
                                                   compositionengine::DisplayCreationArgsBuilder()
                                                           .setId(DEFAULT_DISPLAY_ID)
                                                           .setPixels({DEFAULT_DISPLAY_WIDTH,
                                                                       DEFAULT_DISPLAY_HEIGHT})
                                                           .setPowerAdvisor(&mPowerAdvisor)
                                                           .build());

    constexpr bool kIsPrimary = true;
    auto injector = FakeDisplayDeviceInjector(mFlinger, compositionDisplay,
                                              ui::DisplayConnectionType::Internal,
                                              DEFAULT_DISPLAY_HWC_DISPLAY_ID, kIsPrimary);

    injector.setNativeWindow(mNativeWindow);
    if (injectExtra) {
        injectExtra(injector);
    }

    auto displayDevice = injector.inject();

    Mock::VerifyAndClear(mNativeWindow.get());

    return displayDevice;
}

bool DisplayTransactionTest::hasPhysicalHwcDisplay(HWDisplayId hwcDisplayId) const {
    const auto& map = mFlinger.hwcPhysicalDisplayIdMap();

Loading