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

Commit 83174493 authored by Jorim Jaggi's avatar Jorim Jaggi Committed by android-build-merger
Browse files

Allow for more flexible vsync-offsets

am: e203e04e

Change-Id: I0fedb99a6295c22f1290fef5a4baa6479459010d
parents 085a53d7 e203e04e
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -222,7 +222,13 @@ public:
                // Pretend that the last time this event was handled at the same frame but with the
                // new offset to allow for a seamless offset change without double-firing or
                // skipping.
                listener.mLastEventTime -= (oldPhase - phase);
                nsecs_t diff = oldPhase - phase;
                if (diff > mPeriod / 2) {
                    diff -= mPeriod;
                } else if (diff < -mPeriod / 2) {
                    diff += mPeriod;
                }
                listener.mLastEventTime -= diff;
                mCond.signal();
                return NO_ERROR;
            }
+37 −9
Original line number Diff line number Diff line
@@ -331,11 +331,26 @@ SurfaceFlinger::SurfaceFlinger() : SurfaceFlinger(SkipInitialization) {
    auto listSize = property_get_int32("debug.sf.max_igbp_list_size", int32_t(defaultListSize));
    mMaxGraphicBufferProducerListSize = (listSize > 0) ? size_t(listSize) : defaultListSize;

    property_get("debug.sf.early_phase_offset_ns", value, "0");
    const int earlyWakeupOffsetOffsetNs = atoi(value);
    ALOGI_IF(earlyWakeupOffsetOffsetNs != 0, "Enabling separate early offset");
    mVsyncModulator.setPhaseOffsets(sfVsyncPhaseOffsetNs - earlyWakeupOffsetOffsetNs,
            sfVsyncPhaseOffsetNs);
    property_get("debug.sf.early_phase_offset_ns", value, "-1");
    const int earlySfOffsetNs = atoi(value);

    property_get("debug.sf.early_gl_phase_offset_ns", value, "-1");
    const int earlyGlSfOffsetNs = atoi(value);

    property_get("debug.sf.early_app_phase_offset_ns", value, "-1");
    const int earlyAppOffsetNs = atoi(value);

    property_get("debug.sf.early_gl_app_phase_offset_ns", value, "-1");
    const int earlyGlAppOffsetNs = atoi(value);

    const VSyncModulator::Offsets earlyOffsets =
            {earlySfOffsetNs != -1 ? earlySfOffsetNs : sfVsyncPhaseOffsetNs,
            earlyAppOffsetNs != -1 ? earlyAppOffsetNs : vsyncPhaseOffsetNs};
    const VSyncModulator::Offsets earlyGlOffsets =
            {earlyGlSfOffsetNs != -1 ? earlyGlSfOffsetNs : sfVsyncPhaseOffsetNs,
            earlyGlAppOffsetNs != -1 ? earlyGlAppOffsetNs : vsyncPhaseOffsetNs};
    mVsyncModulator.setPhaseOffsets(earlyOffsets, earlyGlOffsets,
            {sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs});

    // We should be reading 'persist.sys.sf.color_saturation' here
    // but since /data may be encrypted, we need to wait until after vold
@@ -662,7 +677,7 @@ void SurfaceFlinger::init() {
                                                },
                                                "sfEventThread");
    mEventQueue->setEventThread(mSFEventThread.get());
    mVsyncModulator.setEventThread(mSFEventThread.get());
    mVsyncModulator.setEventThreads(mSFEventThread.get(), mEventThread.get());

    // Get a RenderEngine for the given display / config (can't fail)
    getBE().mRenderEngine =
@@ -4207,9 +4222,22 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
    colorizer.bold(result);
    result.append("DispSync configuration: ");
    colorizer.reset(result);
    result.appendFormat("app phase %" PRId64 " ns, sf phase %" PRId64 " ns, early sf phase %" PRId64
        " ns, present offset %" PRId64 " ns (refresh %" PRId64 " ns)",
        vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs, mVsyncModulator.getEarlyPhaseOffset(),
    const auto [sfEarlyOffset, appEarlyOffset] = mVsyncModulator.getEarlyOffsets();
    const auto [sfEarlyGlOffset, appEarlyGlOffset] = mVsyncModulator.getEarlyGlOffsets();
    result.appendFormat(
        "app phase %" PRId64 " ns, "
        "sf phase %" PRId64 " ns, "
        "early app phase %" PRId64 " ns, "
        "early sf phase %" PRId64 " ns, "
        "early app gl phase %" PRId64 " ns, "
        "early sf gl phase %" PRId64 " ns, "
        "present offset %" PRId64 " ns (refresh %" PRId64 " ns)",
        vsyncPhaseOffsetNs,
        sfVsyncPhaseOffsetNs,
        appEarlyOffset,
        sfEarlyOffset,
        appEarlyGlOffset,
        sfEarlyOffset,
        dispSyncPresentTimeOffset, activeConfig->getVsyncPeriod());
    result.append("\n");

+65 −42
Original line number Diff line number Diff line
@@ -36,6 +36,11 @@ private:

public:

    struct Offsets {
        nsecs_t sf;
        nsecs_t app;
    };

    enum TransactionStart {
        EARLY,
        NORMAL
@@ -43,21 +48,32 @@ public:

    // Sets the phase offsets
    //
    // early: the phase offset when waking up early. May be the same as late, in which case we don't
    //        shift offsets.
    // late: the regular sf phase offset.
    void setPhaseOffsets(nsecs_t early, nsecs_t late) {
        mEarlyPhaseOffset = early;
        mLatePhaseOffset = late;
        mPhaseOffset = late;
    // sfEarly: The phase offset when waking up SF early, which happens when marking a transaction
    //          as early. May be the same as late, in which case we don't shift offsets.
    // sfEarlyGl: Like sfEarly, but only if we used GL composition. If we use both GL composition
    //            and the transaction was marked as early, we'll use sfEarly.
    // sfLate: The regular SF vsync phase offset.
    // appEarly: Like sfEarly, but for the app-vsync
    // appEarlyGl: Like sfEarlyGl, but for the app-vsync.
    // appLate: The regular app vsync phase offset.
    void setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late) {
        mEarlyOffsets = early;
        mEarlyGlOffsets = earlyGl;
        mLateOffsets = late;
        mOffsets = late;
    }

    Offsets getEarlyOffsets() const {
        return mEarlyOffsets;
    }

    nsecs_t getEarlyPhaseOffset() const {
        return mEarlyPhaseOffset;
    Offsets getEarlyGlOffsets() const {
        return mEarlyGlOffsets;
    }

    void setEventThread(EventThread* eventThread) {
        mEventThread = eventThread;
    void setEventThreads(EventThread* sfEventThread, EventThread* appEventThread) {
        mSfEventThread = sfEventThread;
        mAppEventThread = appEventThread;
    }

    void setTransactionStart(TransactionStart transactionStart) {
@@ -71,63 +87,70 @@ public:
            return;
        }
        mTransactionStart = transactionStart;
        updatePhaseOffsets();
        updateOffsets();
    }

    void onTransactionHandled() {
        if (mTransactionStart == TransactionStart::NORMAL) return;
        mTransactionStart = TransactionStart::NORMAL;
        updatePhaseOffsets();
        updateOffsets();
    }

    void onRefreshed(bool usedRenderEngine) {
        bool updatePhaseOffsetsNeeded = false;
        bool updateOffsetsNeeded = false;
        if (mRemainingEarlyFrameCount > 0) {
            mRemainingEarlyFrameCount--;
            updatePhaseOffsetsNeeded = true;
            updateOffsetsNeeded = true;
        }
        if (usedRenderEngine != mLastFrameUsedRenderEngine) {
            mLastFrameUsedRenderEngine = usedRenderEngine;
            updatePhaseOffsetsNeeded = true;
            updateOffsetsNeeded = true;
        }
        if (updatePhaseOffsetsNeeded) {
            updatePhaseOffsets();
        if (updateOffsetsNeeded) {
            updateOffsets();
        }
    }

private:

    void updatePhaseOffsets() {

        // Do not change phase offsets if disabled.
        if (mEarlyPhaseOffset == mLatePhaseOffset) return;
    void updateOffsets() {
        const Offsets desired = getOffsets();
        const Offsets current = mOffsets;

        if (shouldUseEarlyOffset()) {
            if (mPhaseOffset != mEarlyPhaseOffset) {
                if (mEventThread) {
                    mEventThread->setPhaseOffset(mEarlyPhaseOffset);
        bool changed = false;
        if (desired.sf != current.sf) {
            mSfEventThread->setPhaseOffset(desired.sf);
            changed = true;
        }
                mPhaseOffset = mEarlyPhaseOffset;
        if (desired.app != current.app) {
            mAppEventThread->setPhaseOffset(desired.app);
            changed = true;
        }
        } else {
            if (mPhaseOffset != mLatePhaseOffset) {
                if (mEventThread) {
                    mEventThread->setPhaseOffset(mLatePhaseOffset);

        if (changed) {
            mOffsets = desired;
        }
                mPhaseOffset = mLatePhaseOffset;
    }

    Offsets getOffsets() {
        if (mTransactionStart == TransactionStart::EARLY || mRemainingEarlyFrameCount > 0) {
            return mEarlyOffsets;
        } else if (mLastFrameUsedRenderEngine) {
            return mEarlyGlOffsets;
        } else {
            return mLateOffsets;
        }
    }

    bool shouldUseEarlyOffset() {
        return mTransactionStart == TransactionStart::EARLY || mLastFrameUsedRenderEngine
                || mRemainingEarlyFrameCount > 0;
    }
    Offsets mLateOffsets;
    Offsets mEarlyOffsets;
    Offsets mEarlyGlOffsets;

    EventThread* mSfEventThread = nullptr;
    EventThread* mAppEventThread = nullptr;

    std::atomic<Offsets> mOffsets;

    nsecs_t mLatePhaseOffset = 0;
    nsecs_t mEarlyPhaseOffset = 0;
    EventThread* mEventThread = nullptr;
    std::atomic<nsecs_t> mPhaseOffset = 0;
    std::atomic<TransactionStart> mTransactionStart = TransactionStart::NORMAL;
    std::atomic<bool> mLastFrameUsedRenderEngine = false;
    std::atomic<int> mRemainingEarlyFrameCount = 0;