Skip to content

Commit 59bbef0

Browse files
author
Jeff Brown
committed
Improve animation timing.
Detect when a vsync message was significantly delayed which may indicate that a frame was skipped. When this happens, update the frame time to reflect the approximate start time of the current frame instead of the start time of the frame that was skipped a long time ago. Removed an unnecessary call to getCurrentPlayTime() in the animator framework. The result was always zero and the call just made the code confusing. Bug: 6443611 Change-Id: I92b24f7ffd74c59b75a727b6bfc0bb51fc92a73a
1 parent 2321301 commit 59bbef0

File tree

2 files changed

+29
-6
lines changed

2 files changed

+29
-6
lines changed

core/java/android/animation/ValueAnimator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -910,7 +910,7 @@ private void start(boolean playBackwards) {
910910
animationHandler.mPendingAnimations.add(this);
911911
if (mStartDelay == 0) {
912912
// This sets the initial value of the animation, prior to actually starting it running
913-
setCurrentPlayTime(getCurrentPlayTime());
913+
setCurrentPlayTime(0);
914914
mPlayingState = STOPPED;
915915
mRunning = true;
916916
notifyStartListeners();

core/java/android/view/Choreographer.java

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ protected Choreographer initialValue() {
9292
private boolean mFrameScheduled;
9393
private boolean mCallbacksRunning;
9494
private long mLastFrameTimeNanos;
95+
private long mFrameIntervalNanos;
9596

9697
/**
9798
* Callback type: Input callback. Runs first.
@@ -116,6 +117,8 @@ private Choreographer(Looper looper) {
116117
mHandler = new FrameHandler(looper);
117118
mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null;
118119
mLastFrameTimeNanos = Long.MIN_VALUE;
120+
mFrameIntervalNanos = (long)(1000000000 /
121+
new Display(Display.DEFAULT_DISPLAY, null).getRefreshRate());
119122

120123
mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
121124
for (int i = 0; i <= CALLBACK_LAST; i++) {
@@ -343,17 +346,37 @@ private void scheduleFrameLocked(long now) {
343346
}
344347

345348
void doFrame(long timestampNanos, int frame) {
349+
final long startNanos;
346350
synchronized (mLock) {
347351
if (!mFrameScheduled) {
348352
return; // no work to do
349353
}
350-
mFrameScheduled = false;
351-
mLastFrameTimeNanos = timestampNanos;
352-
}
353354

354-
final long startNanos;
355-
if (DEBUG) {
356355
startNanos = System.nanoTime();
356+
final long jitterNanos = startNanos - timestampNanos;
357+
if (jitterNanos >= mFrameIntervalNanos) {
358+
final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
359+
if (DEBUG) {
360+
Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms "
361+
+ "which is more than the frame interval of "
362+
+ (mFrameIntervalNanos * 0.000001f) + " ms! "
363+
+ "Setting frame time to " + (lastFrameOffset * 0.000001f)
364+
+ " ms in the past.");
365+
}
366+
timestampNanos = startNanos - lastFrameOffset;
367+
}
368+
369+
if (timestampNanos < mLastFrameTimeNanos) {
370+
if (DEBUG) {
371+
Log.d(TAG, "Frame time appears to be going backwards. May be due to a "
372+
+ "previously skipped frame. Waiting for next vsync");
373+
}
374+
scheduleVsyncLocked();
375+
return;
376+
}
377+
378+
mFrameScheduled = false;
379+
mLastFrameTimeNanos = timestampNanos;
357380
}
358381

359382
doCallbacks(Choreographer.CALLBACK_INPUT);

0 commit comments

Comments
 (0)