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

Commit 51e888ba authored by Ady Abraham's avatar Ady Abraham
Browse files

SF: allow more than one client to use eEarly[Start|End] flags

Bug: 191969790
Test: SF unit tests
Change-Id: I0a21600eba986857e0231e02cb4d59fb108e9bd3
Merged-In: I0a21600eba986857e0231e02cb4d59fb108e9bd3
parent 6a409e17
Loading
Loading
Loading
Loading
+28 −12
Original line number Diff line number Diff line
@@ -46,27 +46,36 @@ VsyncModulator::VsyncConfig VsyncModulator::setVsyncConfigSet(const VsyncConfigS
    return updateVsyncConfigLocked();
}

VsyncModulator::VsyncConfigOpt VsyncModulator::setTransactionSchedule(
        TransactionSchedule schedule) {
VsyncModulator::VsyncConfigOpt VsyncModulator::setTransactionSchedule(TransactionSchedule schedule,
                                                                      const sp<IBinder>& token) {
    std::lock_guard<std::mutex> lock(mMutex);
    switch (schedule) {
        case Schedule::EarlyStart:
            ALOGW_IF(mEarlyWakeup, "%s: Duplicate EarlyStart", __FUNCTION__);
            mEarlyWakeup = true;
            if (token) {
                mEarlyWakeupRequests.emplace(token);
                token->linkToDeath(this);
            } else {
                ALOGW("%s: EarlyStart requested without a valid token", __func__);
            }
            break;
        case Schedule::EarlyEnd:
            ALOGW_IF(!mEarlyWakeup, "%s: Unexpected EarlyEnd", __FUNCTION__);
            mEarlyWakeup = false;
        case Schedule::EarlyEnd: {
            if (token && mEarlyWakeupRequests.erase(token) > 0) {
                token->unlinkToDeath(this);
            } else {
                ALOGW("%s: Unexpected EarlyEnd", __func__);
            }
            break;
        }
        case Schedule::Late:
            // No change to mEarlyWakeup for non-explicit states.
            break;
    }

    if (mTraceDetailedInfo) {
        ATRACE_INT("mEarlyWakeup", mEarlyWakeup);
        ATRACE_INT("mEarlyWakeup", static_cast<int>(mEarlyWakeupRequests.size()));
    }

    if (!mEarlyWakeup && schedule == Schedule::EarlyEnd) {
    if (mEarlyWakeupRequests.empty() && schedule == Schedule::EarlyEnd) {
        mEarlyTransactionFrames = MIN_EARLY_TRANSACTION_FRAMES;
        mEarlyTransactionStartTime = mNow();
    }
@@ -76,7 +85,7 @@ VsyncModulator::VsyncConfigOpt VsyncModulator::setTransactionSchedule(
        return std::nullopt;
    }
    mTransactionSchedule = schedule;
    return updateVsyncConfig();
    return updateVsyncConfigLocked();
}

VsyncModulator::VsyncConfigOpt VsyncModulator::onTransactionCommit() {
@@ -128,8 +137,8 @@ VsyncModulator::VsyncConfig VsyncModulator::getVsyncConfig() const {
const VsyncModulator::VsyncConfig& VsyncModulator::getNextVsyncConfig() const {
    // Early offsets are used if we're in the middle of a refresh rate
    // change, or if we recently begin a transaction.
    if (mEarlyWakeup || mTransactionSchedule == Schedule::EarlyEnd || mEarlyTransactionFrames > 0 ||
        mRefreshRateChangePending) {
    if (!mEarlyWakeupRequests.empty() || mTransactionSchedule == Schedule::EarlyEnd ||
        mEarlyTransactionFrames > 0 || mRefreshRateChangePending) {
        return mVsyncConfigSet.early;
    } else if (mEarlyGpuFrames > 0) {
        return mVsyncConfigSet.earlyGpu;
@@ -160,4 +169,11 @@ VsyncModulator::VsyncConfig VsyncModulator::updateVsyncConfigLocked() {
    return offsets;
}

void VsyncModulator::binderDied(const wp<IBinder>& who) {
    std::lock_guard<std::mutex> lock(mMutex);
    mEarlyWakeupRequests.erase(who);

    static_cast<void>(updateVsyncConfigLocked());
}

} // namespace android::scheduler
+16 −3
Original line number Diff line number Diff line
@@ -19,8 +19,10 @@
#include <chrono>
#include <mutex>
#include <optional>
#include <unordered_set>

#include <android-base/thread_annotations.h>
#include <binder/IBinder.h>
#include <utils/Timers.h>

namespace android::scheduler {
@@ -35,7 +37,7 @@ enum class TransactionSchedule {
};

// Modulates VSYNC phase depending on transaction schedule and refresh rate changes.
class VsyncModulator {
class VsyncModulator : public IBinder::DeathRecipient {
public:
    // Number of frames to keep early offsets after an early transaction or GPU composition.
    // This acts as a low-pass filter in case subsequent transactions are delayed, or if the
@@ -91,7 +93,8 @@ public:
    [[nodiscard]] VsyncConfig setVsyncConfigSet(const VsyncConfigSet&) EXCLUDES(mMutex);

    // Changes offsets in response to transaction flags or commit.
    [[nodiscard]] VsyncConfigOpt setTransactionSchedule(TransactionSchedule);
    [[nodiscard]] VsyncConfigOpt setTransactionSchedule(TransactionSchedule,
                                                        const sp<IBinder>& = {}) EXCLUDES(mMutex);
    [[nodiscard]] VsyncConfigOpt onTransactionCommit();

    // Called when we send a refresh rate change to hardware composer, so that
@@ -104,6 +107,10 @@ public:

    [[nodiscard]] VsyncConfigOpt onDisplayRefresh(bool usedGpuComposition);

protected:
    // Called from unit tests as well
    void binderDied(const wp<IBinder>&) override EXCLUDES(mMutex);

private:
    const VsyncConfig& getNextVsyncConfig() const REQUIRES(mMutex);
    [[nodiscard]] VsyncConfig updateVsyncConfig() EXCLUDES(mMutex);
@@ -116,8 +123,14 @@ private:

    using Schedule = TransactionSchedule;
    std::atomic<Schedule> mTransactionSchedule = Schedule::Late;
    std::atomic<bool> mEarlyWakeup = false;

    struct WpHash {
        size_t operator()(const wp<IBinder>& p) const {
            return std::hash<IBinder*>()(p.unsafe_get());
        }
    };

    std::unordered_set<wp<IBinder>, WpHash> mEarlyWakeupRequests GUARDED_BY(mMutex);
    std::atomic<bool> mRefreshRateChangePending = false;

    std::atomic<int> mEarlyTransactionFrames = 0;
+5 −4
Original line number Diff line number Diff line
@@ -3157,7 +3157,7 @@ void SurfaceFlinger::initScheduler(const DisplayDeviceState& displayState) {
                                                                      hal::PowerMode::OFF);

    mVsyncConfiguration = getFactory().createVsyncConfiguration(currRefreshRate);
    mVsyncModulator.emplace(mVsyncConfiguration->getCurrentConfigs());
    mVsyncModulator = sp<VsyncModulator>::make(mVsyncConfiguration->getCurrentConfigs());

    // start the EventThread
    mScheduler = getFactory().createScheduler(*mRefreshRateConfigs, *this);
@@ -3437,9 +3437,10 @@ uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) {
    return setTransactionFlags(flags, TransactionSchedule::Late);
}

uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags, TransactionSchedule schedule) {
uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags, TransactionSchedule schedule,
                                             const sp<IBinder>& token) {
    uint32_t old = mTransactionFlags.fetch_or(flags);
    modulateVsync(&VsyncModulator::setTransactionSchedule, schedule);
    modulateVsync(&VsyncModulator::setTransactionSchedule, schedule, token);
    if ((old & flags) == 0) signalTransaction();
    return old;
}
@@ -3659,7 +3660,7 @@ void SurfaceFlinger::queueTransaction(TransactionState& state) {
        return TransactionSchedule::Late;
    }(state.flags);

    setTransactionFlags(eTransactionFlushNeeded, schedule);
    setTransactionFlags(eTransactionFlushNeeded, schedule, state.applyToken);
}

void SurfaceFlinger::waitForSynchronousTransaction(
+2 −2
Original line number Diff line number Diff line
@@ -851,7 +851,7 @@ private:
    // but there is no need to try and wake up immediately to do it. Rather we rely on
    // onFrameAvailable or another layer update to wake us up.
    void setTraversalNeeded();
    uint32_t setTransactionFlags(uint32_t flags, TransactionSchedule);
    uint32_t setTransactionFlags(uint32_t flags, TransactionSchedule, const sp<IBinder>& = {});
    void commitTransaction() REQUIRES(mStateLock);
    void commitOffscreenLayers();
    bool transactionIsReadyToBeApplied(
@@ -1389,7 +1389,7 @@ private:
    std::unique_ptr<scheduler::VsyncConfiguration> mVsyncConfiguration;

    // Optional to defer construction until PhaseConfiguration is created.
    std::optional<scheduler::VsyncModulator> mVsyncModulator;
    sp<VsyncModulator> mVsyncModulator;

    std::unique_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs;
    std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats;
+2 −1
Original line number Diff line number Diff line
@@ -230,7 +230,8 @@ public:
                std::make_unique<scheduler::RefreshRateStats>(*mFlinger->mTimeStats, currFps,
                                                              /*powerMode=*/hal::PowerMode::OFF);
        mFlinger->mVsyncConfiguration = mFactory.createVsyncConfiguration(currFps);
        mFlinger->mVsyncModulator.emplace(mFlinger->mVsyncConfiguration->getCurrentConfigs());
        mFlinger->mVsyncModulator = sp<scheduler::VsyncModulator>::make(
                mFlinger->mVsyncConfiguration->getCurrentConfigs());

        mScheduler = new TestableScheduler(std::move(vsyncController), std::move(vsyncTracker),
                                           *mFlinger->mRefreshRateConfigs, *(callback ?: this));
Loading