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

Commit 6d414b56 authored by Alec Mouri's avatar Alec Mouri
Browse files

[SurfaceFlinger] Adjust missed frame tracking

Before, missed frame tracking may be inaccurate if a frame takes longer
than one vsync and either an invalidate message is not immediately
scheduled afterwards, or the frame takes almost as long as two vsyncs
but manages to be on time to be presented for that second vsync. Those
scenarios can cause visual jank, but they are not tracked by missed
frames which affects testing.

* Rename the previous missedFrames to pendingFrames
* pendingFrames is used to check for backpressure propagation so there
is no change to device behavior
* Compute a new missedFrames count by relaxing the check for
pendingFrames - if the expected present time of the previous frame was
earlier than the actual present time then that frame was missed. We add
half a vsync of slop to correct for scheduling drift.

Bug: 143647283
Test: boots
Test: systrace
Change-Id: I0f76d06737f5182c512ca6f36b332b68192250c3
parent 89290018
Loading
Loading
Loading
Loading
+46 −11
Original line number Diff line number Diff line
@@ -1026,7 +1026,7 @@ bool SurfaceFlinger::performSetActiveConfig() {
    ATRACE_CALL();
    ALOGV("performSetActiveConfig");
    if (mCheckPendingFence) {
        if (previousFrameMissed()) {
        if (previousFramePending()) {
            // fence has not signaled yet. wait for the next invalidate
            mEventQueue->invalidate();
            return true;
@@ -1773,13 +1773,17 @@ void SurfaceFlinger::updateVrFlinger() {
    setTransactionFlags(eDisplayTransactionNeeded);
}

bool SurfaceFlinger::previousFrameMissed(int graceTimeMs) NO_THREAD_SAFETY_ANALYSIS {
    ATRACE_CALL();
sp<Fence> SurfaceFlinger::previousFrameFence() NO_THREAD_SAFETY_ANALYSIS {
    // We are storing the last 2 present fences. If sf's phase offset is to be
    // woken up before the actual vsync but targeting the next vsync, we need to check
    // fence N-2
    const sp<Fence>& fence = mVSyncModulator->getOffsets().sf > 0 ? mPreviousPresentFences[0]
    return mVSyncModulator->getOffsets().sf > 0 ? mPreviousPresentFences[0]
                                                : mPreviousPresentFences[1];
}

bool SurfaceFlinger::previousFramePending(int graceTimeMs) NO_THREAD_SAFETY_ANALYSIS {
    ATRACE_CALL();
    const sp<Fence>& fence = previousFrameFence();

    if (fence == Fence::NO_FENCE) {
        return false;
@@ -1792,6 +1796,16 @@ bool SurfaceFlinger::previousFrameMissed(int graceTimeMs) NO_THREAD_SAFETY_ANALY
    return (fence->getStatus() == Fence::Status::Unsignaled);
}

nsecs_t SurfaceFlinger::previousFramePresentTime() NO_THREAD_SAFETY_ANALYSIS {
    const sp<Fence>& fence = previousFrameFence();

    if (fence == Fence::NO_FENCE) {
        return Fence::SIGNAL_TIME_INVALID;
    }

    return fence->getSignalTime();
}

void SurfaceFlinger::populateExpectedPresentTime() {
    DisplayStatInfo stats;
    mScheduler->getDisplayStatInfo(&stats);
@@ -1809,6 +1823,7 @@ void SurfaceFlinger::onMessageReceived(int32_t what) NO_THREAD_SAFETY_ANALYSIS {
            // calculate the expected present time once and use the cached
            // value throughout this frame to make sure all layers are
            // seeing this same value.
            const nsecs_t lastExpectedPresentTime = mExpectedPresentTime.load();
            populateExpectedPresentTime();

            // When Backpressure propagation is enabled we want to give a small grace period
@@ -1819,12 +1834,32 @@ void SurfaceFlinger::onMessageReceived(int32_t what) NO_THREAD_SAFETY_ANALYSIS {
                     (mPropagateBackpressureClientComposition || !mHadClientComposition))
                    ? 1
                    : 0;
            const TracedOrdinal<bool> frameMissed = {"FrameMissed",
                                                     previousFrameMissed(

            // Pending frames may trigger backpressure propagation.
            const TracedOrdinal<bool> framePending = {"PrevFramePending",
                                                      previousFramePending(
                                                              graceTimeForPresentFenceMs)};
            const TracedOrdinal<bool> hwcFrameMissed = {"HwcFrameMissed",

            // Frame missed counts for metrics tracking.
            // A frame is missed if the prior frame is still pending. If no longer pending,
            // then we still count the frame as missed if the predicted present time
            // was further in the past than when the fence actually fired.

            // Add some slop to correct for drift. This should generally be
            // smaller than a typical frame duration, but should not be so small
            // that it reports reasonable drift as a missed frame.
            DisplayStatInfo stats;
            mScheduler->getDisplayStatInfo(&stats);
            const nsecs_t frameMissedSlop = stats.vsyncPeriod / 2;
            const nsecs_t previousPresentTime = previousFramePresentTime();
            const TracedOrdinal<bool> frameMissed =
                    {"PrevFrameMissed",
                     framePending ||
                             (previousPresentTime >= 0 &&
                              (lastExpectedPresentTime < previousPresentTime - frameMissedSlop))};
            const TracedOrdinal<bool> hwcFrameMissed = {"PrevHwcFrameMissed",
                                                        mHadDeviceComposition && frameMissed};
            const TracedOrdinal<bool> gpuFrameMissed = {"GpuFrameMissed",
            const TracedOrdinal<bool> gpuFrameMissed = {"PrevGpuFrameMissed",
                                                        mHadClientComposition && frameMissed};

            if (frameMissed) {
@@ -1844,7 +1879,7 @@ void SurfaceFlinger::onMessageReceived(int32_t what) NO_THREAD_SAFETY_ANALYSIS {
                mGpuFrameMissedCount++;
            }

            if (frameMissed && mPropagateBackpressure) {
            if (framePending && mPropagateBackpressure) {
                if ((hwcFrameMissed && !gpuFrameMissed) ||
                    mPropagateBackpressureClientComposition) {
                    signalLayerUpdate();
+15 −1
Original line number Diff line number Diff line
@@ -839,7 +839,21 @@ private:

    bool isDisplayConfigAllowed(HwcConfigIndexType configId) const REQUIRES(mStateLock);

    bool previousFrameMissed(int graceTimeMs = 0);
    // Gets the fence for the previous frame.
    // Must be called on the main thread.
    sp<Fence> previousFrameFence();

    // Whether the previous frame has not yet been presented to the display.
    // If graceTimeMs is positive, this method waits for at most the provided
    // grace period before reporting if the frame missed.
    // Must be called on the main thread.
    bool previousFramePending(int graceTimeMs = 0);

    // Returns the previous time that the frame was presented. If the frame has
    // not been presented yet, then returns Fence::SIGNAL_TIME_PENDING. If there
    // is no pending frame, then returns Fence::SIGNAL_TIME_INVALID.
    // Must be called on the main thread.
    nsecs_t previousFramePresentTime();

    // Populates the expected present time for this frame. For negative offsets, performs a
    // correction using the predicted vsync for the next frame instead.