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

Commit b8dda5c2 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "[MD] Single refresh rate selection"

parents 290e61ee 69b58e83
Loading
Loading
Loading
Loading
+128 −11
Original line number Diff line number Diff line
@@ -57,6 +57,39 @@
        }                                                            \
    } 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)
@@ -662,6 +695,7 @@ template <typename S, typename T>
auto Scheduler::applyPolicy(S Policy::*statePtr, T&& newState) -> GlobalSignals {
    DisplayModePtr newMode;
    GlobalSignals consideredSignals;
    std::vector<DisplayModeConfig> displayModeConfigs;

    bool refreshRateChanged = false;
    bool frameRateOverridesChanged;
@@ -674,9 +708,27 @@ auto Scheduler::applyPolicy(S Policy::*statePtr, T&& newState) -> GlobalSignals
        if (currentState == newState) return {};
        currentState = std::forward<T>(newState);

        const auto [rankings, signals] = getRankedDisplayModes();
        newMode = rankings.front().displayModePtr;
        consideredSignals = signals;
        displayModeConfigs = getBestDisplayModeConfigs();

        // mPolicy holds the current mode, using the current mode we find out
        // what display is currently being tracked through the policy and
        // then find the DisplayModeConfig for that display. So that
        // later we check if the policy mode has changed for the same display in policy.
        // If mPolicy mode isn't available then we take the first display from the best display
        // modes as the candidate for policy changes and frame rate overrides.
        // TODO(b/240743786) Update the single display based assumptions and make mode changes
        // and mPolicy per display.
        const DisplayModeConfig& displayModeConfigForCurrentPolicy = mPolicy.mode
                ? *std::find_if(displayModeConfigs.begin(), displayModeConfigs.end(),
                                [&](const auto& displayModeConfig) REQUIRES(mPolicyLock) {
                                    return displayModeConfig.displayModePtr
                                                   ->getPhysicalDisplayId() ==
                                            mPolicy.mode->getPhysicalDisplayId();
                                })
                : displayModeConfigs.front();

        newMode = displayModeConfigForCurrentPolicy.displayModePtr;
        consideredSignals = displayModeConfigForCurrentPolicy.signals;
        frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps());

        if (mPolicy.mode == newMode) {
@@ -691,9 +743,7 @@ auto Scheduler::applyPolicy(S Policy::*statePtr, T&& newState) -> GlobalSignals
        }
    }
    if (refreshRateChanged) {
        mSchedulerCallback.requestDisplayMode(std::move(newMode),
                                              consideredSignals.idle ? DisplayModeEvent::None
                                                                     : DisplayModeEvent::Changed);
        mSchedulerCallback.requestDisplayModes(std::move(displayModeConfigs));
    }
    if (frameRateOverridesChanged) {
        mSchedulerCallback.triggerOnFrameRateOverridesChanged();
@@ -701,12 +751,68 @@ auto Scheduler::applyPolicy(S Policy::*statePtr, T&& newState) -> GlobalSignals
    return consideredSignals;
}

auto Scheduler::getRankedDisplayModes()
        -> std::pair<std::vector<RefreshRateRanking>, GlobalSignals> {
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();

    const auto configs = holdRefreshRateConfigs();
    std::vector<RefreshRateRankingsAndSignals> refreshRateRankingsAndSignalsPerDisplay;
    refreshRateRankingsAndSignalsPerDisplay.reserve(mDisplays.size());

    const auto displayModeSelectionParams = getDisplayModeSelectionParams();

    std::for_each(mDisplays.begin(), mDisplays.end(), [&](const auto& display) {
        const auto& [refreshRateRankings, globalSignals] =
                display.second->holdRefreshRateConfigs()
                        ->getRankedRefreshRates(displayModeSelectionParams.layerRequirements,
                                                displayModeSelectionParams.globalSignals);
        refreshRateRankingsAndSignalsPerDisplay.emplace_back(
                RefreshRateRankingsAndSignals{refreshRateRankings, globalSignals});
    });

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

    Fps chosenFps = std::max_element(aggregatedScoresPerFps.begin(), aggregatedScoresPerFps.end(),
                                     [](const auto& max, const auto& current) {
                                         return max.second.totalScore <= current.second.totalScore;
                                     })
                            ->first;

    return getDisplayModeConfigsForTheChosenFps(chosenFps, refreshRateRankingsAndSignalsPerDisplay);
}

std::vector<DisplayModeConfig> Scheduler::getDisplayModeConfigsForTheChosenFps(
        Fps chosenFps,
        const std::vector<RefreshRateRankingsAndSignals>& refreshRateRankingsAndSignalsPerDisplay)
        const {
    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});
                              break;
                          }
                      }
                  });
    return displayModeConfigs;
}

DisplayModeSelectionParams Scheduler::getDisplayModeSelectionParams() const {
    const bool powerOnImminent = mDisplayPowerTimer &&
            (mPolicy.displayPowerMode != hal::PowerMode::ON ||
             mPolicy.displayPowerTimer == TimerState::Reset);
@@ -715,7 +821,18 @@ auto Scheduler::getRankedDisplayModes()
                                .idle = mPolicy.idleTimer == TimerState::Expired,
                                .powerOnImminent = powerOnImminent};

    return configs->getRankedRefreshRates(mPolicy.contentRequirements, signals);
    return {mPolicy.contentRequirements, signals};
}

auto Scheduler::getRankedDisplayModes()
        -> std::pair<std::vector<RefreshRateRanking>, GlobalSignals> {
    ATRACE_CALL();

    const auto configs = holdRefreshRateConfigs();

    const auto displayModeSelectionParams = getDisplayModeSelectionParams();
    return configs->getRankedRefreshRates(displayModeSelectionParams.layerRequirements,
                                          displayModeSelectionParams.globalSignals);
}

DisplayModePtr Scheduler::getPreferredDisplayMode() {
+52 −3
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include <mutex>
#include <optional>
#include <unordered_map>
#include <utility>

// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
@@ -32,9 +33,11 @@
#include <ui/GraphicTypes.h>
#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"

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

#include "Display/DisplayMap.h"
#include "EventThread.h"
#include "FrameRateOverrideMappings.h"
#include "LayerHistory.h"
@@ -83,11 +86,22 @@ class TokenManager;

namespace scheduler {

using GlobalSignals = RefreshRateConfigs::GlobalSignals;

// Config representing the DisplayMode and considered signals for the Display.
struct DisplayModeConfig {
    const GlobalSignals signals;
    const DisplayModePtr displayModePtr;

    DisplayModeConfig(GlobalSignals signals, DisplayModePtr displayModePtr)
          : signals(signals), displayModePtr(std::move(displayModePtr)) {}
};

struct ISchedulerCallback {
    using DisplayModeEvent = scheduler::DisplayModeEvent;

    virtual void setVsyncEnabled(bool) = 0;
    virtual void requestDisplayMode(DisplayModePtr, DisplayModeEvent) = 0;
    virtual void requestDisplayModes(std::vector<DisplayModeConfig>) = 0;
    virtual void kernelTimerChanged(bool expired) = 0;
    virtual void triggerOnFrameRateOverridesChanged() = 0;

@@ -95,6 +109,25 @@ 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 LayerRequirements and GlobalSignals to be considered for the display mode selection.
struct DisplayModeSelectionParams {
    std::vector<RefreshRateConfigs::LayerRequirement> layerRequirements;
    GlobalSignals globalSignals;
};

// 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;

@@ -237,6 +270,9 @@ public:
        return mLayerHistory.getLayerFramerate(now, id);
    }

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

private:
    friend class TestableScheduler;

@@ -260,8 +296,6 @@ private:

    void setVsyncPeriod(nsecs_t period);

    using GlobalSignals = RefreshRateConfigs::GlobalSignals;

    struct Policy;

    // Sets the S state of the policy to the T value under mPolicyLock, and chooses a display mode
@@ -274,6 +308,17 @@ private:
    std::pair<std::vector<RefreshRateRanking>, GlobalSignals> getRankedDisplayModes()
            REQUIRES(mPolicyLock);

    // 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;

    // Returns the DisplayModeSelectionParams to be considered for the
    // DisplayMode selection based on the current Policy and GlobalSignals.
    DisplayModeSelectionParams getDisplayModeSelectionParams() const REQUIRES(mPolicyLock);

    bool updateFrameRateOverrides(GlobalSignals, Fps displayRefreshRate) REQUIRES(mPolicyLock);

    void dispatchCachedReportedMode() REQUIRES(mPolicyLock) EXCLUDES(mRefreshRateConfigsLock);
@@ -323,6 +368,10 @@ 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;

    struct Policy {
        // Policy for choosing the display mode.
        LayerHistory::Summary contentRequirements;
+4 −0
Original line number Diff line number Diff line
@@ -138,6 +138,10 @@ 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());
}
+27 −14
Original line number Diff line number Diff line
@@ -2938,7 +2938,7 @@ void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken,
        if (display->isPrimary()) {
            mScheduler->setRefreshRateConfigs(display->holdRefreshRateConfigs());
        }

        mScheduler->registerDisplay(display);
        dispatchDisplayHotplugEvent(display->getPhysicalId(), true);
    }

@@ -2954,6 +2954,7 @@ void SurfaceFlinger::processDisplayRemoved(const wp<IBinder>& displayToken) {
            releaseVirtualDisplay(display->getVirtualId());
        } else {
            dispatchDisplayHotplugEvent(display->getPhysicalId(), false);
            mScheduler->unregisterDisplay(display->getPhysicalId());
        }
    }

@@ -2990,6 +2991,8 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken,
            display->disconnect();
            if (display->isVirtual()) {
                releaseVirtualDisplay(display->getVirtualId());
            } else {
                mScheduler->unregisterDisplay(display->getPhysicalId());
            }
        }

@@ -3319,25 +3322,34 @@ void SurfaceFlinger::updateCursorAsync() {
    mCompositionEngine->updateCursorAsync(refreshArgs);
}

void SurfaceFlinger::requestDisplayMode(DisplayModePtr mode, DisplayModeEvent event) {
void SurfaceFlinger::requestDisplayModes(
        std::vector<scheduler::DisplayModeConfig> displayModeConfigs) {
    if (mBootStage != BootStage::FINISHED) {
        ALOGV("Currently in the boot stage, skipping display mode changes");
        return;
    }

    ATRACE_CALL();
    // If this is called from the main thread mStateLock must be locked before
    // Currently the only way to call this function from the main thread is from
    // Scheduler::chooseRefreshRateForContent

    ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);

    const auto display = getDefaultDisplayDeviceLocked();
    if (!display || mBootStage != BootStage::FINISHED) {
        return;
    }
    ATRACE_CALL();

    if (!display->refreshRateConfigs().isModeAllowed(mode->getId())) {
        ALOGV("Skipping disallowed mode %d", mode->getId().value());
        return;
    std::for_each(displayModeConfigs.begin(), displayModeConfigs.end(),
                  [&](const auto& config) REQUIRES(mStateLock) {
                      const auto& displayModePtr = config.displayModePtr;
                      if (const auto display =
                                  getDisplayDeviceLocked(displayModePtr->getPhysicalDisplayId());
                          display->refreshRateConfigs().isModeAllowed(displayModePtr->getId())) {
                          const auto event = config.signals.idle ? DisplayModeEvent::None
                                                                 : DisplayModeEvent::Changed;
                          setDesiredActiveMode({displayModePtr, event});
                      } else {
                          ALOGV("Skipping disallowed mode %d for display %" PRId64,
                                displayModePtr->getId().value(), display->getPhysicalId().value);
                      }

    setDesiredActiveMode({std::move(mode), event});
                  });
}

void SurfaceFlinger::triggerOnFrameRateOverridesChanged() {
@@ -3386,6 +3398,7 @@ void SurfaceFlinger::initScheduler(const sp<const DisplayDevice>& display) {

        mScheduler->createVsyncSchedule(features);
        mScheduler->setRefreshRateConfigs(std::move(configs));
        mScheduler->registerDisplay(display);
    }
    setVsyncEnabled(false);
    mScheduler->startTimers();
+2 −2
Original line number Diff line number Diff line
@@ -631,8 +631,8 @@ private:

    // Toggles hardware VSYNC by calling into HWC.
    void setVsyncEnabled(bool) override;
    // Sets the desired display mode if allowed by policy.
    void requestDisplayMode(DisplayModePtr, DisplayModeEvent) override;
    // Sets the desired display mode per display if allowed by policy .
    void requestDisplayModes(std::vector<scheduler::DisplayModeConfig>) override;
    // Called when kernel idle timer has expired. Used to update the refresh rate overlay.
    void kernelTimerChanged(bool expired) override;
    // Called when the frame rate override list changed to trigger an event.
Loading