Merge "Remove some per-frame allocations in Choreographer" into udc-dev

This commit is contained in:
Rachel Lee
2023-03-02 02:09:58 +00:00
committed by Android (Google) Code Review
2 changed files with 84 additions and 71 deletions

View File

@@ -197,6 +197,7 @@ public final class Choreographer {
private int mFPSDivisor = 1; private int mFPSDivisor = 1;
private DisplayEventReceiver.VsyncEventData mLastVsyncEventData = private DisplayEventReceiver.VsyncEventData mLastVsyncEventData =
new DisplayEventReceiver.VsyncEventData(); new DisplayEventReceiver.VsyncEventData();
private final FrameData mFrameData = new FrameData();
/** /**
* Contains information about the current frame for jank-tracking, * Contains information about the current frame for jank-tracking,
@@ -789,7 +790,7 @@ public final class Choreographer {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, Trace.traceBegin(Trace.TRACE_TAG_VIEW,
"Choreographer#doFrame " + vsyncEventData.preferredFrameTimeline().vsyncId); "Choreographer#doFrame " + vsyncEventData.preferredFrameTimeline().vsyncId);
} }
FrameData frameData = new FrameData(frameTimeNanos, vsyncEventData); mFrameData.update(frameTimeNanos, vsyncEventData);
synchronized (mLock) { synchronized (mLock) {
if (!mFrameScheduled) { if (!mFrameScheduled) {
traceMessage("Frame not scheduled"); traceMessage("Frame not scheduled");
@@ -827,7 +828,7 @@ public final class Choreographer {
+ " ms in the past."); + " ms in the past.");
} }
} }
frameData = getUpdatedFrameData(frameTimeNanos, frameData, jitterNanos); mFrameData.update(frameTimeNanos, mDisplayEventReceiver, jitterNanos);
} }
if (frameTimeNanos < mLastFrameTimeNanos) { if (frameTimeNanos < mLastFrameTimeNanos) {
@@ -862,17 +863,16 @@ public final class Choreographer {
AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS); AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
mFrameInfo.markInputHandlingStart(); mFrameInfo.markInputHandlingStart();
doCallbacks(Choreographer.CALLBACK_INPUT, frameData, frameIntervalNanos); doCallbacks(Choreographer.CALLBACK_INPUT, frameIntervalNanos);
mFrameInfo.markAnimationsStart(); mFrameInfo.markAnimationsStart();
doCallbacks(Choreographer.CALLBACK_ANIMATION, frameData, frameIntervalNanos); doCallbacks(Choreographer.CALLBACK_ANIMATION, frameIntervalNanos);
doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameData, doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameIntervalNanos);
frameIntervalNanos);
mFrameInfo.markPerformTraversalsStart(); 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 { } finally {
AnimationUtils.unlockAnimationClock(); AnimationUtils.unlockAnimationClock();
Trace.traceEnd(Trace.TRACE_TAG_VIEW); 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; CallbackRecord callbacks;
long frameTimeNanos = frameData.mFrameTimeNanos; long frameTimeNanos = mFrameData.getFrameTimeNanos();
synchronized (mLock) { synchronized (mLock) {
// We use "now" to determine when callbacks become due because it's possible // 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 // for earlier processing phases in a frame to post callbacks that should run
@@ -925,7 +925,7 @@ public final class Choreographer {
} }
frameTimeNanos = now - lastFrameOffset; frameTimeNanos = now - lastFrameOffset;
mLastFrameTimeNanos = frameTimeNanos; 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 + ", action=" + c.action + ", token=" + c.token
+ ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime)); + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
} }
c.run(frameData); c.run(mFrameData);
} }
} finally { } finally {
synchronized (mLock) { synchronized (mLock) {
@@ -1039,15 +1039,19 @@ public final class Choreographer {
/** Holds data that describes one possible VSync frame event to render at. */ /** Holds data that describes one possible VSync frame event to render at. */
public static class FrameTimeline { public static class FrameTimeline {
FrameTimeline(long vsyncId, long expectedPresentTimeNanos, long deadlineNanos) { private long mVsyncId = FrameInfo.INVALID_VSYNC_ID;
this.mVsyncId = vsyncId; private long mExpectedPresentationTimeNanos = -1;
this.mExpectedPresentTimeNanos = expectedPresentTimeNanos; private long mDeadlineNanos = -1;
this.mDeadlineNanos = deadlineNanos;
FrameTimeline() {
// Intentionally empty; defined so that it is not API/public by default.
} }
private long mVsyncId; void update(long vsyncId, long expectedPresentationTimeNanos, long deadlineNanos) {
private long mExpectedPresentTimeNanos; mVsyncId = vsyncId;
private long mDeadlineNanos; mExpectedPresentationTimeNanos = expectedPresentationTimeNanos;
mDeadlineNanos = deadlineNanos;
}
/** /**
* The id that corresponds to this frame timeline, used to correlate a frame * The id that corresponds to this frame timeline, used to correlate a frame
@@ -1062,7 +1066,7 @@ public final class Choreographer {
* presented. * presented.
*/ */
public long getExpectedPresentationTimeNanos() { public long getExpectedPresentationTimeNanos() {
return mExpectedPresentTimeNanos; return mExpectedPresentationTimeNanos;
} }
/** /**
@@ -1079,20 +1083,15 @@ public final class Choreographer {
* information including deadline and expected present time. * information including deadline and expected present time.
*/ */
public static class FrameData { 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 long mFrameTimeNanos;
private final FrameTimeline[] mFrameTimelines; private final FrameTimeline[] mFrameTimelines =
new FrameTimeline[DisplayEventReceiver.VsyncEventData.FRAME_TIMELINES_LENGTH];
private int mPreferredFrameTimelineIndex; private int mPreferredFrameTimelineIndex;
void updateFrameData(long frameTimeNanos, int newPreferredFrameTimelineIndex) { FrameData() {
mFrameTimeNanos = frameTimeNanos; for (int i = 0; i < mFrameTimelines.length; i++) {
mPreferredFrameTimelineIndex = newPreferredFrameTimelineIndex; mFrameTimelines[i] = new FrameTimeline();
}
} }
/** The time in nanoseconds when the frame started being rendered. */ /** The time in nanoseconds when the frame started being rendered. */
@@ -1113,49 +1112,58 @@ public final class Choreographer {
return mFrameTimelines[mPreferredFrameTimelineIndex]; return mFrameTimelines[mPreferredFrameTimelineIndex];
} }
private FrameTimeline[] convertFrameTimelines( /**
DisplayEventReceiver.VsyncEventData vsyncEventData) { * Update the frame data with a {@code DisplayEventReceiver.VsyncEventData} received from
FrameTimeline[] frameTimelines = * native.
new FrameTimeline[vsyncEventData.frameTimelines.length]; */
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++) { for (int i = 0; i < vsyncEventData.frameTimelines.length; i++) {
DisplayEventReceiver.VsyncEventData.FrameTimeline frameTimeline = DisplayEventReceiver.VsyncEventData.FrameTimeline frameTimeline =
vsyncEventData.frameTimelines[i]; vsyncEventData.frameTimelines[i];
frameTimelines[i] = new FrameTimeline(frameTimeline.vsyncId, mFrameTimelines[i].update(frameTimeline.vsyncId,
frameTimeline.expectedPresentTime, frameTimeline.deadline); frameTimeline.expectedPresentationTime, frameTimeline.deadline);
} }
return frameTimelines;
}
}
/**
* 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(); * Update the frame data when the frame is late.
if (newPreferredDeadline < minimumDeadline) { *
DisplayEventReceiver.VsyncEventData latestVsyncEventData = * @param jitterNanos currentTime - frameTime
mDisplayEventReceiver.getLatestVsyncEventData(); */
return new FrameData(frameTimeNanos, latestVsyncEventData); void update(
} else { long frameTimeNanos, DisplayEventReceiver displayEventReceiver, long jitterNanos) {
frameData.updateFrameData(frameTimeNanos, newPreferredIndex); int newPreferredIndex = 0;
return frameData; final long minimumDeadline =
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 < mFrameTimelines.length - 1
&& mFrameTimelines[newPreferredIndex].getDeadlineNanos() < minimumDeadline) {
newPreferredIndex++;
}
long newPreferredDeadline = mFrameTimelines[newPreferredIndex].getDeadlineNanos();
if (newPreferredDeadline < minimumDeadline) {
DisplayEventReceiver.VsyncEventData latestVsyncEventData =
displayEventReceiver.getLatestVsyncEventData();
update(frameTimeNanos, latestVsyncEventData);
} else {
update(frameTimeNanos, newPreferredIndex);
}
}
void update(long frameTimeNanos, int newPreferredFrameTimelineIndex) {
mFrameTimeNanos = frameTimeNanos;
mPreferredFrameTimelineIndex = newPreferredFrameTimelineIndex;
} }
} }

View File

@@ -145,11 +145,16 @@ public abstract class DisplayEventReceiver {
static final FrameTimeline[] INVALID_FRAME_TIMELINES = static final FrameTimeline[] INVALID_FRAME_TIMELINES =
{new FrameTimeline(FrameInfo.INVALID_VSYNC_ID, Long.MAX_VALUE, Long.MAX_VALUE)}; {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 { public static class FrameTimeline {
FrameTimeline(long vsyncId, long expectedPresentTime, long deadline) { FrameTimeline(long vsyncId, long expectedPresentationTime, long deadline) {
this.vsyncId = vsyncId; this.vsyncId = vsyncId;
this.expectedPresentTime = expectedPresentTime; this.expectedPresentationTime = expectedPresentationTime;
this.deadline = deadline; this.deadline = deadline;
} }
@@ -158,7 +163,7 @@ public abstract class DisplayEventReceiver {
public final long vsyncId; public final long vsyncId;
// The frame timestamp for when the frame is expected to be presented. // 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 // The frame deadline timestamp in {@link System#nanoTime()} timebase that it is
// allotted for the frame to be completed. // allotted for the frame to be completed.