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

Commit 754c98a5 authored by Alec Mouri's avatar Alec Mouri
Browse files

Add pending period to DispSync.

When the period is updated due to a config change, cache the period
and don't immediately update the model until we actually observe updated
vsyncs from the hardware.

To make this more reliable, force hardware vsync to be enabled when we
first initiate a refresh rate change.

Also, override offsets with custom offsets while the period is in flux,
so that we don't fall into bad offsets when ramping up to 90hz

Bug: 128848865
Bug: 128860504
Test: systrace
Change-Id: I6aa87ad29b3effce9067a1d54d444023c7362b22
parent 381ac014
Loading
Loading
Loading
Loading
+30 −12
Original line number Original line Diff line number Diff line
@@ -210,8 +210,7 @@ public:
            const nsecs_t baseTime = now - mReferenceTime;
            const nsecs_t baseTime = now - mReferenceTime;
            const nsecs_t numPeriodsSinceReference = baseTime / mPeriod;
            const nsecs_t numPeriodsSinceReference = baseTime / mPeriod;
            const nsecs_t predictedReference = mReferenceTime + numPeriodsSinceReference * mPeriod;
            const nsecs_t predictedReference = mReferenceTime + numPeriodsSinceReference * mPeriod;
            const nsecs_t phaseCorrection = mPhase + listener.mPhase;
            listener.mLastEventTime = predictedReference + mPhase + listener.mPhase;
            listener.mLastEventTime = predictedReference + phaseCorrection;
            // If we're very close in time to the predicted last event time,
            // If we're very close in time to the predicted last event time,
            // then we need to back up the last event time so that we can
            // then we need to back up the last event time so that we can
            // attempt to fire an event immediately.
            // attempt to fire an event immediately.
@@ -279,7 +278,6 @@ public:
                return NO_ERROR;
                return NO_ERROR;
            }
            }
        }
        }

        return BAD_VALUE;
        return BAD_VALUE;
    }
    }


@@ -525,21 +523,40 @@ void DispSync::beginResync() {
    mNumResyncSamples = 0;
    mNumResyncSamples = 0;
}
}


bool DispSync::addResyncSample(nsecs_t timestamp) {
bool DispSync::addResyncSample(nsecs_t timestamp, bool* periodChanged) {
    Mutex::Autolock lock(mMutex);
    Mutex::Autolock lock(mMutex);


    ALOGV("[%s] addResyncSample(%" PRId64 ")", mName, ns2us(timestamp));
    ALOGV("[%s] addResyncSample(%" PRId64 ")", mName, ns2us(timestamp));


    size_t idx = (mFirstResyncSample + mNumResyncSamples) % MAX_RESYNC_SAMPLES;
    *periodChanged = false;
    const size_t idx = (mFirstResyncSample + mNumResyncSamples) % MAX_RESYNC_SAMPLES;
    mResyncSamples[idx] = timestamp;
    mResyncSamples[idx] = timestamp;
    if (mNumResyncSamples == 0) {
    if (mNumResyncSamples == 0) {
        mPhase = 0;
        mPhase = 0;
        mReferenceTime = timestamp;
        ALOGV("[%s] First resync sample: mPeriod = %" PRId64 ", mPhase = 0, "
        ALOGV("[%s] First resync sample: mPeriod = %" PRId64 ", mPhase = 0, "
              "mReferenceTime = %" PRId64,
              "mReferenceTime = %" PRId64,
              mName, ns2us(mPeriod), ns2us(mReferenceTime));
              mName, ns2us(mPeriod), ns2us(timestamp));
        mThread->updateModel(mPeriod, mPhase, mReferenceTime);
    } else if (mPendingPeriod > 0) {
        // mNumResyncSamples > 0, so priorIdx won't overflow
        const size_t priorIdx = (mFirstResyncSample + mNumResyncSamples - 1) % MAX_RESYNC_SAMPLES;
        const nsecs_t lastTimestamp = mResyncSamples[priorIdx];

        const nsecs_t observedVsync = std::abs(timestamp - lastTimestamp);
        if (std::abs(observedVsync - mPendingPeriod) < std::abs(observedVsync - mPeriod)) {
            // Observed vsync is closer to the pending period, so reset the
            // model and flush the pending period.
            resetLocked();
            mPeriod = mPendingPeriod;
            mPendingPeriod = 0;
            if (mTraceDetailedInfo) {
                ATRACE_INT("DispSync:PendingPeriod", mPendingPeriod);
            }
            *periodChanged = true;
        }
    }
    }
    // Always update the reference time with the most recent timestamp.
    mReferenceTime = timestamp;
    mThread->updateModel(mPeriod, mPhase, mReferenceTime);


    if (mNumResyncSamples < MAX_RESYNC_SAMPLES) {
    if (mNumResyncSamples < MAX_RESYNC_SAMPLES) {
        mNumResyncSamples++;
        mNumResyncSamples++;
@@ -562,7 +579,7 @@ bool DispSync::addResyncSample(nsecs_t timestamp) {


    // Check against kErrorThreshold / 2 to add some hysteresis before having to
    // Check against kErrorThreshold / 2 to add some hysteresis before having to
    // resync again
    // resync again
    bool modelLocked = mModelUpdated && mError < (kErrorThreshold / 2);
    bool modelLocked = mModelUpdated && mError < (kErrorThreshold / 2) && mPendingPeriod == 0;
    ALOGV("[%s] addResyncSample returning %s", mName, modelLocked ? "locked" : "unlocked");
    ALOGV("[%s] addResyncSample returning %s", mName, modelLocked ? "locked" : "unlocked");
    return !modelLocked;
    return !modelLocked;
}
}
@@ -594,9 +611,10 @@ status_t DispSync::changePhaseOffset(Callback* callback, nsecs_t phase) {


void DispSync::setPeriod(nsecs_t period) {
void DispSync::setPeriod(nsecs_t period) {
    Mutex::Autolock lock(mMutex);
    Mutex::Autolock lock(mMutex);
    mPeriod = period;
    if (mTraceDetailedInfo) {
    mPhase = 0;
        ATRACE_INT("DispSync:PendingPeriod", period);
    mThread->updateModel(mPeriod, mPhase, mReferenceTime);
    }
    mPendingPeriod = period;
}
}


nsecs_t DispSync::getPeriod() {
nsecs_t DispSync::getPeriod() {
+14 −2
Original line number Original line Diff line number Diff line
@@ -49,7 +49,7 @@ public:
    virtual void reset() = 0;
    virtual void reset() = 0;
    virtual bool addPresentFence(const std::shared_ptr<FenceTime>&) = 0;
    virtual bool addPresentFence(const std::shared_ptr<FenceTime>&) = 0;
    virtual void beginResync() = 0;
    virtual void beginResync() = 0;
    virtual bool addResyncSample(nsecs_t timestamp) = 0;
    virtual bool addResyncSample(nsecs_t timestamp, bool* periodChanged) = 0;
    virtual void endResync() = 0;
    virtual void endResync() = 0;
    virtual void setPeriod(nsecs_t period) = 0;
    virtual void setPeriod(nsecs_t period) = 0;
    virtual nsecs_t getPeriod() = 0;
    virtual nsecs_t getPeriod() = 0;
@@ -119,7 +119,13 @@ public:
    // addPresentFence returns true indicating that the model has drifted away
    // addPresentFence returns true indicating that the model has drifted away
    // from the hardware vsync events.
    // from the hardware vsync events.
    void beginResync() override;
    void beginResync() override;
    bool addResyncSample(nsecs_t timestamp) override;
    // Adds a vsync sample to the dispsync model. The timestamp is the time
    // of the vsync event that fired. periodChanged will return true if the
    // vsync period was detected to have changed to mPendingPeriod.
    //
    // This method will return true if more vsync samples are needed to lock
    // down the DispSync model, and false otherwise.
    bool addResyncSample(nsecs_t timestamp, bool* periodChanged) override;
    void endResync() override;
    void endResync() override;


    // The setPeriod method sets the vsync event model's period to a specific
    // The setPeriod method sets the vsync event model's period to a specific
@@ -199,6 +205,12 @@ private:
    // nanoseconds.
    // nanoseconds.
    nsecs_t mPeriod;
    nsecs_t mPeriod;


    // mPendingPeriod is the proposed period change in nanoseconds.
    // If mPendingPeriod differs from mPeriod and is nonzero, it will
    // be flushed to mPeriod when we detect that the hardware switched
    // vsync frequency.
    nsecs_t mPendingPeriod = 0;

    // mPhase is the phase offset of the modeled vsync events.  It is the
    // mPhase is the phase offset of the modeled vsync events.  It is the
    // number of nanoseconds from time 0 to the first vsync event.
    // number of nanoseconds from time 0 to the first vsync event.
    nsecs_t mPhase;
    nsecs_t mPhase;
+2 −2
Original line number Original line Diff line number Diff line
@@ -68,8 +68,8 @@ public:
    void dump(std::string& result) const override;
    void dump(std::string& result) const override;


private:
private:
    Offsets getmDefaultRefreshRateOffsets() { return mDefaultRefreshRateOffsets; }
    Offsets getDefaultRefreshRateOffsets() { return mDefaultRefreshRateOffsets; }
    Offsets getmHighRefreshRateOffsets() { return mHighRefreshRateOffsets; }
    Offsets getHighRefreshRateOffsets() { return mHighRefreshRateOffsets; }


    std::atomic<RefreshRateConfigs::RefreshRateType> mRefreshRateType =
    std::atomic<RefreshRateConfigs::RefreshRateType> mRefreshRateType =
            RefreshRateConfigs::RefreshRateType::DEFAULT;
            RefreshRateConfigs::RefreshRateType::DEFAULT;
+3 −3
Original line number Original line Diff line number Diff line
@@ -255,7 +255,6 @@ void Scheduler::setRefreshSkipCount(int count) {


void Scheduler::setVsyncPeriod(const nsecs_t period) {
void Scheduler::setVsyncPeriod(const nsecs_t period) {
    std::lock_guard<std::mutex> lock(mHWVsyncLock);
    std::lock_guard<std::mutex> lock(mHWVsyncLock);
    mPrimaryDispSync->reset();
    mPrimaryDispSync->setPeriod(period);
    mPrimaryDispSync->setPeriod(period);


    if (!mPrimaryHWVsyncEnabled) {
    if (!mPrimaryHWVsyncEnabled) {
@@ -265,12 +264,13 @@ void Scheduler::setVsyncPeriod(const nsecs_t period) {
    }
    }
}
}


void Scheduler::addResyncSample(const nsecs_t timestamp) {
void Scheduler::addResyncSample(const nsecs_t timestamp, bool* periodChanged) {
    bool needsHwVsync = false;
    bool needsHwVsync = false;
    *periodChanged = false;
    { // Scope for the lock
    { // Scope for the lock
        std::lock_guard<std::mutex> lock(mHWVsyncLock);
        std::lock_guard<std::mutex> lock(mHWVsyncLock);
        if (mPrimaryHWVsyncEnabled) {
        if (mPrimaryHWVsyncEnabled) {
            needsHwVsync = mPrimaryDispSync->addResyncSample(timestamp);
            needsHwVsync = mPrimaryDispSync->addResyncSample(timestamp, periodChanged);
        }
        }
    }
    }


+3 −1
Original line number Original line Diff line number Diff line
@@ -142,7 +142,9 @@ public:
    // Creates a callback for resyncing.
    // Creates a callback for resyncing.
    ResyncCallback makeResyncCallback(GetVsyncPeriod&& getVsyncPeriod);
    ResyncCallback makeResyncCallback(GetVsyncPeriod&& getVsyncPeriod);
    void setRefreshSkipCount(int count);
    void setRefreshSkipCount(int count);
    void addResyncSample(const nsecs_t timestamp);
    // Passes a vsync sample to DispSync. periodChange will be true if DipSync
    // detected that the vsync period changed, and false otherwise.
    void addResyncSample(const nsecs_t timestamp, bool* periodChanged);
    void addPresentFence(const std::shared_ptr<FenceTime>& fenceTime);
    void addPresentFence(const std::shared_ptr<FenceTime>& fenceTime);
    void setIgnorePresentFences(bool ignore);
    void setIgnorePresentFences(bool ignore);
    nsecs_t expectedPresentTime();
    nsecs_t expectedPresentTime();
Loading