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

Commit 5fa57fc2 authored by Rachel Lee's avatar Rachel Lee
Browse files

Update vsync info on late frame (Choreographer).

The binder to get latest vsync info is only called if the frame data is
not already available in the current collection of frame timelines. This
means the frame is sufficiently late so it should be fine to call.

Bug: 236889264
Test: atest ChoreographerTest
Change-Id: I4952c2e16cc152f65a513cf340dc2cd9fc694675
parent f82b8020
Loading
Loading
Loading
Loading
+45 −40
Original line number Diff line number Diff line
@@ -765,11 +765,12 @@ public final class Choreographer {
                startNanos = System.nanoTime();
                final long jitterNanos = startNanos - frameTimeNanos;
                if (jitterNanos >= frameIntervalNanos) {
                    long lastFrameOffset = 0;
                    frameTimeNanos = startNanos;
                    if (frameIntervalNanos == 0) {
                        Log.i(TAG, "Vsync data empty due to timeout");
                    } else {
                        lastFrameOffset = jitterNanos % frameIntervalNanos;
                        long lastFrameOffset = jitterNanos % frameIntervalNanos;
                        frameTimeNanos = frameTimeNanos - lastFrameOffset;
                        final long skippedFrames = jitterNanos / frameIntervalNanos;
                        if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
                            Log.i(TAG, "Skipped " + skippedFrames + " frames!  "
@@ -785,8 +786,7 @@ public final class Choreographer {
                                    + " ms in the past.");
                        }
                    }
                    frameTimeNanos = startNanos - lastFrameOffset;
                    frameData.updateFrameData(frameTimeNanos);
                    frameData = getUpdatedFrameData(frameTimeNanos, frameData, jitterNanos);
                }

                if (frameTimeNanos < mLastFrameTimeNanos) {
@@ -884,7 +884,7 @@ public final class Choreographer {
                    }
                    frameTimeNanos = now - lastFrameOffset;
                    mLastFrameTimeNanos = frameTimeNanos;
                    frameData.updateFrameData(frameTimeNanos);
                    frameData = getUpdatedFrameData(frameTimeNanos, frameData, jitterNanos);
                }
            }
        }
@@ -998,9 +998,6 @@ public final class Choreographer {

    /** Holds data that describes one possible VSync frame event to render at. */
    public static class FrameTimeline {
        static final FrameTimeline INVALID_FRAME_TIMELINE = new FrameTimeline(
                FrameInfo.INVALID_VSYNC_ID, Long.MAX_VALUE, Long.MAX_VALUE);

        FrameTimeline(long vsyncId, long expectedPresentTimeNanos, long deadlineNanos) {
            this.mVsyncId = vsyncId;
            this.mExpectedPresentTimeNanos = expectedPresentTimeNanos;
@@ -1019,11 +1016,6 @@ public final class Choreographer {
            return mVsyncId;
        }

        /** Reset the vsync ID to invalid. */
        void resetVsyncId() {
            mVsyncId = FrameInfo.INVALID_VSYNC_ID;
        }

        /**
         * The time in {@link System#nanoTime()} timebase which this frame is expected to be
         * presented.
@@ -1046,39 +1038,20 @@ public final class Choreographer {
     * information including deadline and expected present time.
     */
    public static class FrameData {
        static final FrameTimeline[] INVALID_FRAME_TIMELINES = new FrameTimeline[0];
        FrameData() {
            this.mFrameTimelines = INVALID_FRAME_TIMELINES;
            this.mPreferredFrameTimeline = FrameTimeline.INVALID_FRAME_TIMELINE;
        }

        FrameData(long frameTimeNanos, DisplayEventReceiver.VsyncEventData vsyncEventData) {
            FrameTimeline[] frameTimelines =
                    new FrameTimeline[vsyncEventData.frameTimelines.length];
            for (int i = 0; i <  vsyncEventData.frameTimelines.length; i++) {
                DisplayEventReceiver.VsyncEventData.FrameTimeline frameTimeline =
                        vsyncEventData.frameTimelines[i];
                frameTimelines[i] = new FrameTimeline(frameTimeline.vsyncId,
                        frameTimeline.expectedPresentTime, frameTimeline.deadline);
            }
            this.mFrameTimeNanos = frameTimeNanos;
            this.mFrameTimelines = frameTimelines;
            this.mPreferredFrameTimeline =
                    frameTimelines[vsyncEventData.preferredFrameTimelineIndex];
            this.mFrameTimelines = convertFrameTimelines(vsyncEventData);
            this.mPreferredFrameTimelineIndex =
                    vsyncEventData.preferredFrameTimelineIndex;
        }

        private long mFrameTimeNanos;
        private FrameTimeline[] mFrameTimelines;
        private FrameTimeline mPreferredFrameTimeline;
        private final FrameTimeline[] mFrameTimelines;
        private int mPreferredFrameTimelineIndex;

        void updateFrameData(long frameTimeNanos) {
        void updateFrameData(long frameTimeNanos, int newPreferredFrameTimelineIndex) {
            mFrameTimeNanos = frameTimeNanos;
            for (FrameTimeline ft : mFrameTimelines) {
                // The ID is no longer valid because the frame time that was registered with the ID
                // no longer matches.
                // TODO(b/205721584): Ask SF for valid vsync information.
                ft.resetVsyncId();
            }
            mPreferredFrameTimelineIndex = newPreferredFrameTimelineIndex;
        }

        /** The time in nanoseconds when the frame started being rendered. */
@@ -1096,7 +1069,7 @@ public final class Choreographer {
        /** The platform-preferred frame timeline. */
        @NonNull
        public FrameTimeline getPreferredFrameTimeline() {
            return mPreferredFrameTimeline;
            return mFrameTimelines[mPreferredFrameTimelineIndex];
        }

        private FrameTimeline[] convertFrameTimelines(
@@ -1113,6 +1086,38 @@ public final class Choreographer {
        }
    }

    /**
     * Update the frame data when the frame is late.
     *
     * @param jitterNanos currentTime - frameTime
     */
    private FrameData getUpdatedFrameData(long frameTimeNanos, FrameData frameData,
            long jitterNanos) {
        int newPreferredIndex = 0;
        FrameTimeline[] frameTimelines = frameData.getFrameTimelines();
        final long minimumDeadline =
                frameData.getPreferredFrameTimeline().getDeadlineNanos() + jitterNanos;
        // Look for a non-past deadline timestamp in the existing frame data. Otherwise, binder
        // query for new frame data. Note that binder is relatively slow, O(ms), so it is
        // only called when the existing frame data does not hold a valid frame.
        while (newPreferredIndex < frameTimelines.length - 1
                && frameTimelines[newPreferredIndex].getDeadlineNanos()
                < minimumDeadline) {
            newPreferredIndex++;
        }

        long newPreferredDeadline =
                frameData.getFrameTimelines()[newPreferredIndex].getDeadlineNanos();
        if (newPreferredDeadline < minimumDeadline) {
            DisplayEventReceiver.VsyncEventData latestVsyncEventData =
                    mDisplayEventReceiver.getLatestVsyncEventData();
            return new FrameData(frameTimeNanos, latestVsyncEventData);
        } else {
            frameData.updateFrameData(frameTimeNanos, newPreferredIndex);
            return frameData;
        }
    }

    /**
     * Implement this interface to receive a callback to start the next frame. The callback is
     * invoked on the {@link Looper} thread to which the {@link Choreographer} is attached. The