Merge "Remove some per-frame allocations in Choreographer" into udc-dev
This commit is contained in:
@@ -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,49 +1112,58 @@ 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);
|
||||
mFrameTimelines[i].update(frameTimeline.vsyncId,
|
||||
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();
|
||||
if (newPreferredDeadline < minimumDeadline) {
|
||||
DisplayEventReceiver.VsyncEventData latestVsyncEventData =
|
||||
mDisplayEventReceiver.getLatestVsyncEventData();
|
||||
return new FrameData(frameTimeNanos, latestVsyncEventData);
|
||||
} else {
|
||||
frameData.updateFrameData(frameTimeNanos, newPreferredIndex);
|
||||
return frameData;
|
||||
/**
|
||||
* Update the frame data when the frame is late.
|
||||
*
|
||||
* @param jitterNanos currentTime - frameTime
|
||||
*/
|
||||
void update(
|
||||
long frameTimeNanos, DisplayEventReceiver displayEventReceiver, long jitterNanos) {
|
||||
int newPreferredIndex = 0;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user