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 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
Reference in New Issue
Block a user