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

Commit f8e689cf authored by Alec Mouri's avatar Alec Mouri
Browse files

[SurfaceFlinger] fix permanently enabling early offsets.

* Add notion of intended period in DispSync, and use that to detect
whether the simulated period will be changed.
* Propagate that signal to setDesiredActiveConfig, so that we don't fall
into early offsets unnecessarily, which can cause early offsets to
always be enabled.

Bug: 132678707
Test: systrace
Test: swappy test app
Test: scrolling through google news
Change-Id: I18df1b9d949cd534ecbf1c8891b6f88eab8be399
parent d8610435
Loading
Loading
Loading
Loading
+26 −12
Original line number Diff line number Diff line
@@ -115,11 +115,13 @@ public:
    void lockModel() {
        Mutex::Autolock lock(mMutex);
        mModelLocked = true;
        ATRACE_INT("DispSync:ModelLocked", mModelLocked);
    }

    void unlockModel() {
        Mutex::Autolock lock(mMutex);
        mModelLocked = false;
        ATRACE_INT("DispSync:ModelLocked", mModelLocked);
    }

    virtual bool threadLoop() {
@@ -493,7 +495,6 @@ void DispSync::init(bool hasSyncFramework, int64_t dispSyncPresentTimeOffset) {
        ALOGE("Couldn't set SCHED_FIFO for DispSyncThread");
    }

    reset();
    beginResync();

    if (mTraceDetailedInfo && kEnableZeroPhaseTracer) {
@@ -545,17 +546,15 @@ bool DispSync::addPresentFence(const std::shared_ptr<FenceTime>& fenceTime) {
void DispSync::beginResync() {
    Mutex::Autolock lock(mMutex);
    ALOGV("[%s] beginResync", mName);
    mThread->unlockModel();
    mModelUpdated = false;
    mNumResyncSamples = 0;
    resetLocked();
}

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

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

    *periodChanged = false;
    *periodFlushed = false;
    const size_t idx = (mFirstResyncSample + mNumResyncSamples) % MAX_RESYNC_SAMPLES;
    mResyncSamples[idx] = timestamp;
    if (mNumResyncSamples == 0) {
@@ -569,16 +568,20 @@ bool DispSync::addResyncSample(nsecs_t timestamp, bool* periodChanged) {
        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.
        if (std::abs(observedVsync - mPendingPeriod) <= std::abs(observedVsync - mIntendedPeriod)) {
            // Either the observed vsync is closer to the pending period, (and
            // thus we detected a period change), or the period change will
            // no-op. In either case, reset the model and flush the pending
            // period.
            resetLocked();
            mIntendedPeriod = mPendingPeriod;
            mPeriod = mPendingPeriod;
            mPendingPeriod = 0;
            if (mTraceDetailedInfo) {
                ATRACE_INT("DispSync:PendingPeriod", mPendingPeriod);
                ATRACE_INT("DispSync:IntendedPeriod", mIntendedPeriod);
            }
            *periodChanged = true;
            *periodFlushed = true;
        }
    }
    // Always update the reference time with the most recent timestamp.
@@ -609,6 +612,7 @@ bool DispSync::addResyncSample(nsecs_t timestamp, bool* periodChanged) {
    bool modelLocked = mModelUpdated && mError < (kErrorThreshold / 2) && mPendingPeriod == 0;
    ALOGV("[%s] addResyncSample returning %s", mName, modelLocked ? "locked" : "unlocked");
    if (modelLocked) {
        *periodFlushed = true;
        mThread->lockModel();
    }
    return !modelLocked;
@@ -643,10 +647,17 @@ status_t DispSync::changePhaseOffset(Callback* callback, nsecs_t phase) {

void DispSync::setPeriod(nsecs_t period) {
    Mutex::Autolock lock(mMutex);

    const bool pendingPeriodShouldChange =
            period != mIntendedPeriod || (period == mIntendedPeriod && mPendingPeriod != 0);

    if (pendingPeriodShouldChange) {
        mPendingPeriod = period;
    }
    if (mTraceDetailedInfo) {
        ATRACE_INT("DispSync:PendingPeriod", period);
        ATRACE_INT("DispSync:IntendedPeriod", mIntendedPeriod);
        ATRACE_INT("DispSync:PendingPeriod", mPendingPeriod);
    }
    mPendingPeriod = period;
}

nsecs_t DispSync::getPeriod() {
@@ -764,6 +775,9 @@ void DispSync::resetErrorLocked() {
    mPresentSampleOffset = 0;
    mError = 0;
    mZeroErrSamplesCount = 0;
    if (mTraceDetailedInfo) {
        ATRACE_INT64("DispSync:Error", mError);
    }
    for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) {
        mPresentFences[i] = FenceTime::NO_FENCE;
    }
+14 −7
Original line number Diff line number Diff line
@@ -49,7 +49,7 @@ public:
    virtual void reset() = 0;
    virtual bool addPresentFence(const std::shared_ptr<FenceTime>&) = 0;
    virtual void beginResync() = 0;
    virtual bool addResyncSample(nsecs_t timestamp, bool* periodChanged) = 0;
    virtual bool addResyncSample(nsecs_t timestamp, bool* periodFlushed) = 0;
    virtual void endResync() = 0;
    virtual void setPeriod(nsecs_t period) = 0;
    virtual nsecs_t getPeriod() = 0;
@@ -120,17 +120,19 @@ public:
    // from the hardware vsync events.
    void beginResync() 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
    // of the vsync event that fired. periodFlushed 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;
    // periodFlushed will be set to true if mPendingPeriod is flushed to
    // mIntendedPeriod, and false otherwise.
    bool addResyncSample(nsecs_t timestamp, bool* periodFlushed) override;
    void endResync() override;

    // The setPeriod method sets the vsync event model's period to a specific
    // value. This should be used to prime the model when a display is first
    // turned on.  It should NOT be used after that.
    // turned on, or when a refresh rate change is requested.
    void setPeriod(nsecs_t period) override;

    // The getPeriod method returns the current vsync period.
@@ -205,6 +207,11 @@ private:
    // nanoseconds.
    nsecs_t mPeriod;

    // mIntendedPeriod is the intended period of the modeled vsync events in
    // nanoseconds. Under ideal conditions this should be similar if not the
    // same as mPeriod, plus or minus an observed error.
    nsecs_t mIntendedPeriod = 0;

    // 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
@@ -236,8 +243,8 @@ private:
    // process to store information about the hardware vsync event times used
    // to compute the model.
    nsecs_t mResyncSamples[MAX_RESYNC_SAMPLES] = {0};
    size_t mFirstResyncSample;
    size_t mNumResyncSamples;
    size_t mFirstResyncSample = 0;
    size_t mNumResyncSamples = 0;
    int mNumResyncSamplesSincePresent;

    // These member variables store information about the present fences used
+4 −4
Original line number Diff line number Diff line
@@ -280,13 +280,13 @@ void Scheduler::setVsyncPeriod(const nsecs_t period) {
    }
}

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

@@ -415,7 +415,7 @@ void Scheduler::resetKernelTimerCallback() {
    ATRACE_INT("ExpiredKernelIdleTimer", 0);
    std::lock_guard<std::mutex> lock(mCallbackLock);
    if (mGetVsyncPeriod) {
        resyncToHardwareVsync(false, mGetVsyncPeriod());
        resyncToHardwareVsync(true, mGetVsyncPeriod());
    }
}

+8 −3
Original line number Diff line number Diff line
@@ -135,13 +135,18 @@ public:

    void enableHardwareVsync();
    void disableHardwareVsync(bool makeUnavailable);
    // Resyncs the scheduler to hardware vsync.
    // If makeAvailable is true, then hardware vsync will be turned on.
    // Otherwise, if hardware vsync is not already enabled then this method will
    // no-op.
    // The period is the vsync period from the current display configuration.
    void resyncToHardwareVsync(bool makeAvailable, nsecs_t period);
    // Creates a callback for resyncing.
    ResyncCallback makeResyncCallback(GetVsyncPeriod&& getVsyncPeriod);
    void setRefreshSkipCount(int count);
    // 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);
    // Passes a vsync sample to DispSync. periodFlushed will be true if
    // DispSync detected that the vsync period changed, and false otherwise.
    void addResyncSample(const nsecs_t timestamp, bool* periodFlushed);
    void addPresentFence(const std::shared_ptr<FenceTime>& fenceTime);
    void setIgnorePresentFences(bool ignore);
    nsecs_t expectedPresentTime();
+1 −1
Original line number Diff line number Diff line
@@ -116,7 +116,7 @@ public:

    // Called when we detect from vsync signals that the refresh rate changed.
    // This way we can move out of early offsets if no longer necessary.
    void onRefreshRateChangeDetected() {
    void onRefreshRateChangeCompleted() {
        if (!mRefreshRateChangePending) {
            return;
        }
Loading