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

Commit c76126e3 authored by Rachel Lee's avatar Rachel Lee
Browse files

Remove some per-frame allocations in Choreographer

This removes per-frame allocations of
* Choreographer$FrameData
* Choreographer$FrameTimeline[]
* Choreographer$FrameTimeline

Test: hwui_unit_tests using instructions
Test: test app w/ invalidate, android studio profiler
Bug: 258694738
Change-Id: If24e6d884fda67526063828053980fcc17cb6853
parent 77ec4fab
Loading
Loading
Loading
Loading
+74 −66
Original line number Diff line number Diff line
@@ -197,6 +197,7 @@ public final class Choreographer {
    private int mFPSDivisor = 1;
    private DisplayEventReceiver.VsyncEventData mLastVsyncEventData =
            new DisplayEventReceiver.VsyncEventData();
    private final FrameData mFrameData = new FrameData();

    /**
     * Contains information about the current frame for jank-tracking,
@@ -789,7 +790,7 @@ public final class Choreographer {
                Trace.traceBegin(Trace.TRACE_TAG_VIEW,
                        "Choreographer#doFrame " + vsyncEventData.preferredFrameTimeline().vsyncId);
            }
            FrameData frameData = new FrameData(frameTimeNanos, vsyncEventData);
            mFrameData.update(frameTimeNanos, vsyncEventData);
            synchronized (mLock) {
                if (!mFrameScheduled) {
                    traceMessage("Frame not scheduled");
@@ -827,7 +828,7 @@ public final class Choreographer {
                                    + " ms in the past.");
                        }
                    }
                    frameData = getUpdatedFrameData(frameTimeNanos, frameData, jitterNanos);
                    mFrameData.update(frameTimeNanos, mDisplayEventReceiver, jitterNanos);
                }

                if (frameTimeNanos < mLastFrameTimeNanos) {
@@ -862,17 +863,16 @@ public final class Choreographer {
            AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);

            mFrameInfo.markInputHandlingStart();
            doCallbacks(Choreographer.CALLBACK_INPUT, frameData, frameIntervalNanos);
            doCallbacks(Choreographer.CALLBACK_INPUT, frameIntervalNanos);

            mFrameInfo.markAnimationsStart();
            doCallbacks(Choreographer.CALLBACK_ANIMATION, frameData, frameIntervalNanos);
            doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameData,
                    frameIntervalNanos);
            doCallbacks(Choreographer.CALLBACK_ANIMATION, frameIntervalNanos);
            doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameIntervalNanos);

            mFrameInfo.markPerformTraversalsStart();
            doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameData, frameIntervalNanos);
            doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameIntervalNanos);

            doCallbacks(Choreographer.CALLBACK_COMMIT, frameData, frameIntervalNanos);
            doCallbacks(Choreographer.CALLBACK_COMMIT, frameIntervalNanos);
        } finally {
            AnimationUtils.unlockAnimationClock();
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
@@ -886,9 +886,9 @@ public final class Choreographer {
        }
    }

    void doCallbacks(int callbackType, FrameData frameData, long frameIntervalNanos) {
    void doCallbacks(int callbackType, long frameIntervalNanos) {
        CallbackRecord callbacks;
        long frameTimeNanos = frameData.mFrameTimeNanos;
        long frameTimeNanos = mFrameData.getFrameTimeNanos();
        synchronized (mLock) {
            // We use "now" to determine when callbacks become due because it's possible
            // for earlier processing phases in a frame to post callbacks that should run
@@ -925,7 +925,7 @@ public final class Choreographer {
                    }
                    frameTimeNanos = now - lastFrameOffset;
                    mLastFrameTimeNanos = frameTimeNanos;
                    frameData = getUpdatedFrameData(frameTimeNanos, frameData, jitterNanos);
                    mFrameData.update(frameTimeNanos, mDisplayEventReceiver, jitterNanos);
                }
            }
        }
@@ -937,7 +937,7 @@ public final class Choreographer {
                            + ", action=" + c.action + ", token=" + c.token
                            + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
                }
                c.run(frameData);
                c.run(mFrameData);
            }
        } finally {
            synchronized (mLock) {
@@ -1039,15 +1039,19 @@ public final class Choreographer {

    /** Holds data that describes one possible VSync frame event to render at. */
    public static class FrameTimeline {
        FrameTimeline(long vsyncId, long expectedPresentTimeNanos, long deadlineNanos) {
            this.mVsyncId = vsyncId;
            this.mExpectedPresentTimeNanos = expectedPresentTimeNanos;
            this.mDeadlineNanos = deadlineNanos;
        private long mVsyncId = FrameInfo.INVALID_VSYNC_ID;
        private long mExpectedPresentationTimeNanos = -1;
        private long mDeadlineNanos = -1;

        FrameTimeline() {
            // Intentionally empty; defined so that it is not API/public by default.
        }

        private long mVsyncId;
        private long mExpectedPresentTimeNanos;
        private long mDeadlineNanos;
        void update(long vsyncId, long expectedPresentationTimeNanos, long deadlineNanos) {
            mVsyncId = vsyncId;
            mExpectedPresentationTimeNanos = expectedPresentationTimeNanos;
            mDeadlineNanos = deadlineNanos;
        }

        /**
         * The id that corresponds to this frame timeline, used to correlate a frame
@@ -1062,7 +1066,7 @@ public final class Choreographer {
         * presented.
         */
        public long getExpectedPresentationTimeNanos() {
            return mExpectedPresentTimeNanos;
            return mExpectedPresentationTimeNanos;
        }

        /**
@@ -1079,20 +1083,15 @@ public final class Choreographer {
     * information including deadline and expected present time.
     */
    public static class FrameData {
        FrameData(long frameTimeNanos, DisplayEventReceiver.VsyncEventData vsyncEventData) {
            this.mFrameTimeNanos = frameTimeNanos;
            this.mFrameTimelines = convertFrameTimelines(vsyncEventData);
            this.mPreferredFrameTimelineIndex =
                    vsyncEventData.preferredFrameTimelineIndex;
        }

        private long mFrameTimeNanos;
        private final FrameTimeline[] mFrameTimelines;
        private final FrameTimeline[] mFrameTimelines =
                new FrameTimeline[DisplayEventReceiver.VsyncEventData.FRAME_TIMELINES_LENGTH];
        private int mPreferredFrameTimelineIndex;

        void updateFrameData(long frameTimeNanos, int newPreferredFrameTimelineIndex) {
            mFrameTimeNanos = frameTimeNanos;
            mPreferredFrameTimelineIndex = newPreferredFrameTimelineIndex;
        FrameData() {
            for (int i = 0; i < mFrameTimelines.length; i++) {
                mFrameTimelines[i] = new FrameTimeline();
            }
        }

        /** The time in nanoseconds when the frame started being rendered. */
@@ -1113,17 +1112,24 @@ public final class Choreographer {
            return mFrameTimelines[mPreferredFrameTimelineIndex];
        }

        private FrameTimeline[] convertFrameTimelines(
                DisplayEventReceiver.VsyncEventData vsyncEventData) {
            FrameTimeline[] frameTimelines =
                    new FrameTimeline[vsyncEventData.frameTimelines.length];
        /**
         * Update the frame data with a {@code DisplayEventReceiver.VsyncEventData} received from
         * native.
         */
        void update(long frameTimeNanos, DisplayEventReceiver.VsyncEventData vsyncEventData) {
            if (vsyncEventData.frameTimelines.length != mFrameTimelines.length) {
                throw new IllegalStateException(
                        "Length of native frame timelines received does not match Java. Did "
                                + "FRAME_TIMELINES_LENGTH or kFrameTimelinesLength (native) "
                                + "change?");
            }
            mFrameTimeNanos = frameTimeNanos;
            mPreferredFrameTimelineIndex = vsyncEventData.preferredFrameTimelineIndex;
            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);
            }
            return frameTimelines;
                mFrameTimelines[i].update(frameTimeline.vsyncId,
                        frameTimeline.expectedPresentationTime, frameTimeline.deadline);
            }
        }

@@ -1132,30 +1138,32 @@ public final class Choreographer {
         *
         * @param jitterNanos currentTime - frameTime
         */
    private FrameData getUpdatedFrameData(long frameTimeNanos, FrameData frameData,
            long jitterNanos) {
        void update(
                long frameTimeNanos, DisplayEventReceiver displayEventReceiver, long jitterNanos) {
            int newPreferredIndex = 0;
        FrameTimeline[] frameTimelines = frameData.getFrameTimelines();
            final long minimumDeadline =
                frameData.getPreferredFrameTimeline().getDeadlineNanos() + jitterNanos;
                    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) {
            while (newPreferredIndex < mFrameTimelines.length - 1
                    && mFrameTimelines[newPreferredIndex].getDeadlineNanos() < minimumDeadline) {
                newPreferredIndex++;
            }

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

        void update(long frameTimeNanos, int newPreferredFrameTimelineIndex) {
            mFrameTimeNanos = frameTimeNanos;
            mPreferredFrameTimelineIndex = newPreferredFrameTimelineIndex;
        }
    }

+8 −3
Original line number Diff line number Diff line
@@ -145,11 +145,16 @@ public abstract class DisplayEventReceiver {

        static final FrameTimeline[] INVALID_FRAME_TIMELINES =
                {new FrameTimeline(FrameInfo.INVALID_VSYNC_ID, Long.MAX_VALUE, Long.MAX_VALUE)};
        // The amount of frame timeline choices.
        // Must be in sync with VsyncEventData::kFrameTimelinesLength in
        // frameworks/native/libs/gui/include/gui/VsyncEventData.h. If they do not match, a runtime
        // assertion is thrown when Choreographer is processing VsyncEventData.
        static final int FRAME_TIMELINES_LENGTH = 7;

        public static class FrameTimeline {
            FrameTimeline(long vsyncId, long expectedPresentTime, long deadline) {
            FrameTimeline(long vsyncId, long expectedPresentationTime, long deadline) {
                this.vsyncId = vsyncId;
                this.expectedPresentTime = expectedPresentTime;
                this.expectedPresentationTime = expectedPresentationTime;
                this.deadline = deadline;
            }

@@ -158,7 +163,7 @@ public abstract class DisplayEventReceiver {
            public final long vsyncId;

            // The frame timestamp for when the frame is expected to be presented.
            public final long expectedPresentTime;
            public final long expectedPresentationTime;

            // The frame deadline timestamp in {@link System#nanoTime()} timebase that it is
            // allotted for the frame to be completed.