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

Commit 9f10eb9c authored by Ana Krulec's avatar Ana Krulec
Browse files

SF: Don't bump to PERFORMANCE refresh rate with infrequent updates

Testing scenario:
1. Set brightness around 50%-55%, set dark theme.
2. Open Chrome.
3. Click search bar.
4. Can see the cursor show up.
Notice the flickering of the screen.

Explanation:
Kernel idle timer detects inactivity after 100ms, and turns the refresh rate to 60Hz.
When a cursor update happens (every 500ms), SF receives a new frame, notifies kernel,
the refresh rate bumps to 90Hz. After 100ms the kernel again decreases the refresh rate to 60Hz.

Desired goals:
Stop the flickering (eg. changing between 60-90Hz too often).
Continue having low battery impact.

Solution in this AG:
Add logic to SF to detect infrequent updates (for all layers). Description of the algorithm:
1) Store the timestamp of the last two buffers.
2) If the first buffer is older than 250 ms, detect inactivity, go into DEFAULT refresh rate.
3) EXIT: on touch event, layer requests 2 or more frames in less than 250ms.
NOTE: if the application is explicitly requesting 90Hz, SF does not override that. Idle kernel
still kicks in, and the flickering happens.

tested on Chrome v74 Beta, and messaging app.

Test: manual, b/135009095
Bug: 135718869
Change-Id: I72d8cd48b3ec900989afcf0fab1cdc3046b87274
(cherry picked from commit ad083c40)
Merged-In: I72d8cd48b3ec900989afcf0fab1cdc3046b87274
parent 32e89bc5
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -46,11 +46,13 @@ LayerHistory::LayerHistory() {
LayerHistory::~LayerHistory() = default;

std::unique_ptr<LayerHistory::LayerHandle> LayerHistory::createLayer(const std::string name,
                                                                     float minRefreshRate,
                                                                     float maxRefreshRate) {
    const int64_t id = sNextId++;

    std::lock_guard lock(mLock);
    mInactiveLayerInfos.emplace(id, std::make_shared<LayerInfo>(name, maxRefreshRate));
    mInactiveLayerInfos.emplace(id,
                                std::make_shared<LayerInfo>(name, minRefreshRate, maxRefreshRate));
    return std::make_unique<LayerHistory::LayerHandle>(*this, id);
}

+2 −1
Original line number Diff line number Diff line
@@ -53,7 +53,8 @@ public:
    ~LayerHistory();

    // When the layer is first created, register it.
    std::unique_ptr<LayerHandle> createLayer(const std::string name, float maxRefreshRate);
    std::unique_ptr<LayerHandle> createLayer(const std::string name, float minRefreshRate,
                                             float maxRefreshRate);

    // Method for inserting layers and their requested present time into the unordered map.
    void insert(const std::unique_ptr<LayerHandle>& layerHandle, nsecs_t presentTime, bool isHdr);
+3 −2
Original line number Diff line number Diff line
@@ -24,9 +24,10 @@
namespace android {
namespace scheduler {

LayerInfo::LayerInfo(const std::string name, float maxRefreshRate)
LayerInfo::LayerInfo(const std::string name, float minRefreshRate, float maxRefreshRate)
      : mName(name),
        mMinRefreshDuration(1e9f / maxRefreshRate),
        mLowActivityRefreshDuration(1e9f / minRefreshRate),
        mRefreshRateHistory(mMinRefreshDuration) {}

LayerInfo::~LayerInfo() = default;
@@ -41,7 +42,7 @@ void LayerInfo::setLastPresentTime(nsecs_t lastPresentTime) {
    const nsecs_t timeDiff = lastPresentTime - mLastPresentTime;
    mLastPresentTime = lastPresentTime;
    // Ignore time diff that are too high - those are stale values
    if (timeDiff > TIME_EPSILON_NS.count()) return;
    if (timeDiff > OBSOLETE_TIME_EPSILON_NS.count()) return;
    const nsecs_t refreshDuration = (timeDiff > 0) ? timeDiff : mMinRefreshDuration;
    const int fps = 1e9f / refreshDuration;
    mRefreshRateHistory.insertRefreshRate(fps);
+41 −6
Original line number Diff line number Diff line
@@ -86,13 +86,42 @@ class LayerInfo {
        // Checks whether the present time that was inserted HISTORY_SIZE ago is within a
        // certain threshold: TIME_EPSILON_NS.
        bool isRelevant() const {
            const int64_t obsoleteEpsilon = systemTime() - scheduler::TIME_EPSILON_NS.count();
            // The layer had to publish at least HISTORY_SIZE of updates, and the first
            // update should not be older than TIME_EPSILON_NS nanoseconds.
            if (mElements.size() == HISTORY_SIZE &&
                mElements.at(HISTORY_SIZE - 1) > obsoleteEpsilon) {
            if (mElements.size() < 2) {
                return false;
            }

            // The layer had to publish at least HISTORY_SIZE or HISTORY_TIME of updates
            if (mElements.size() != HISTORY_SIZE &&
                mElements.at(mElements.size() - 1) - mElements.at(0) < HISTORY_TIME.count()) {
                return false;
            }

            // The last update should not be older than OBSOLETE_TIME_EPSILON_NS nanoseconds.
            const int64_t obsoleteEpsilon =
                    systemTime() - scheduler::OBSOLETE_TIME_EPSILON_NS.count();
            if (mElements.at(mElements.size() - 1) < obsoleteEpsilon) {
                return false;
            }

            return true;
        }

        bool isLowActivityLayer() const {
            // We want to make sure that we received more than two frames from the layer
            // in order to check low activity.
            if (mElements.size() < 2) {
                return false;
            }

            const int64_t obsoleteEpsilon =
                    systemTime() - scheduler::LOW_ACTIVITY_EPSILON_NS.count();
            // Check the frame before last to determine whether there is low activity.
            // If that frame is older than LOW_ACTIVITY_EPSILON_NS, the layer is sending
            // infrequent updates.
            if (mElements.at(mElements.size() - 2) < obsoleteEpsilon) {
                return true;
            }

            return false;
        }

@@ -101,10 +130,11 @@ class LayerInfo {
    private:
        std::deque<nsecs_t> mElements;
        static constexpr size_t HISTORY_SIZE = 10;
        static constexpr std::chrono::nanoseconds HISTORY_TIME = 500ms;
    };

public:
    LayerInfo(const std::string name, float maxRefreshRate);
    LayerInfo(const std::string name, float minRefreshRate, float maxRefreshRate);
    ~LayerInfo();

    LayerInfo(const LayerInfo&) = delete;
@@ -134,6 +164,10 @@ public:
    // Calculate the average refresh rate.
    float getDesiredRefreshRate() const {
        std::lock_guard lock(mLock);

        if (mPresentTimeHistory.isLowActivityLayer()) {
            return 1e9f / mLowActivityRefreshDuration;
        }
        return mRefreshRateHistory.getRefreshRateAvg();
    }

@@ -165,6 +199,7 @@ public:
private:
    const std::string mName;
    const nsecs_t mMinRefreshDuration;
    const nsecs_t mLowActivityRefreshDuration;
    mutable std::mutex mLock;
    nsecs_t mLastUpdatedTime GUARDED_BY(mLock) = 0;
    nsecs_t mLastPresentTime GUARDED_BY(mLock) = 0;
+5 −2
Original line number Diff line number Diff line
@@ -330,8 +330,11 @@ std::unique_ptr<scheduler::LayerHistory::LayerHandle> Scheduler::registerLayer(
            : RefreshRateType::PERFORMANCE;

    const auto refreshRate = mRefreshRateConfigs.getRefreshRate(refreshRateType);
    const uint32_t fps = (refreshRate) ? refreshRate->fps : 0;
    return mLayerHistory.createLayer(name, fps);
    const uint32_t performanceFps = (refreshRate) ? refreshRate->fps : 0;

    const auto defaultRefreshRate = mRefreshRateConfigs.getRefreshRate(RefreshRateType::DEFAULT);
    const uint32_t defaultFps = (defaultRefreshRate) ? defaultRefreshRate->fps : 0;
    return mLayerHistory.createLayer(name, defaultFps, performanceFps);
}

void Scheduler::addLayerPresentTimeAndHDR(
Loading