Commit 17fab5f8 authored by Michael Thiessen's avatar Michael Thiessen Committed by Commit Bot

VR: Make VSync computation more robust to slow devices.

Previously we were trying to compute the actual refresh rate of the
display, but this isn't possible when the VSync loop runs slow. Instead,
compute the UI thread framerate, which is equivalent to the actual
refresh rate on fast devices, but handles slowdowns appropriately.

Bug: 741090
Change-Id: I35befba210af35f898f500ed70c8ce3b1e31a346
Reviewed-on: https://chromium-review.googlesource.com/568458Reviewed-by: default avatarYash Malik <ymalik@chromium.org>
Commit-Queue: Michael Thiessen <mthiesse@chromium.org>
Cr-Commit-Position: refs/heads/master@{#486569}
parent fbd2fea9
...@@ -487,41 +487,39 @@ public class VrShellDelegate implements ApplicationStatus.ActivityStateListener, ...@@ -487,41 +487,39 @@ public class VrShellDelegate implements ApplicationStatus.ActivityStateListener,
private static final long NANOS_PER_SECOND = 1000000000; private static final long NANOS_PER_SECOND = 1000000000;
private static final long VSYNC_TIMEBASE_UPDATE_DELTA = 1 * NANOS_PER_SECOND; private static final long VSYNC_TIMEBASE_UPDATE_DELTA = 1 * NANOS_PER_SECOND;
private static final double VSYNC_DRIFT_THRESHOLD = 1.2; private static final double MIN_VSYNC_INTERVAL_THRESHOLD = 1.2;
// Estimates based on too few frames are unstable, probably anything above 2 is reasonable. // Estimates based on too few frames are unstable, probably anything above 2 is reasonable.
// Higher numbers will reduce how frequently we update the native vsync base/interval. // Higher numbers will reduce how frequently we update the native vsync base/interval.
private static final int MIN_FRAME_COUNT = 5; private static final int MIN_FRAME_COUNT = 5;
private final long mReportedVSyncNanos; private final long mReportedVSyncNanos;
private final long mMaxVSyncIntervalNanos;
private final long mMinVSyncIntervalNanos; private final long mMinVSyncIntervalNanos;
private long mVSyncTimebaseNanos; private long mVSyncTimebaseNanos;
private long mVSyncIntervalNanos; private long mVSyncIntervalNanos;
private long mVSyncIntervalMicros; private long mVSyncIntervalMicros;
private int mVSyncCount;
private final FrameCallback mCallback = new FrameCallback() { private final FrameCallback mCallback = new FrameCallback() {
@Override @Override
public void doFrame(long frameTimeNanos) { public void doFrame(long frameTimeNanos) {
if (mNativeVrShellDelegate == 0) return; if (mNativeVrShellDelegate == 0) return;
Choreographer.getInstance().postFrameCallback(this); Choreographer.getInstance().postFrameCallback(this);
++mVSyncCount;
if (mVSyncTimebaseNanos == 0) { if (mVSyncTimebaseNanos == 0) {
updateVSyncInterval(frameTimeNanos, mVSyncIntervalNanos); updateVSyncInterval(frameTimeNanos, mVSyncIntervalNanos);
return; return;
} }
if (mVSyncCount < MIN_FRAME_COUNT) return;
long elapsed = frameTimeNanos - mVSyncTimebaseNanos; long elapsed = frameTimeNanos - mVSyncTimebaseNanos;
// If you're hitting the assert below, you probably added the callback twice. // If you're hitting the assert below, you probably added the callback twice.
assert elapsed != 0; assert elapsed != 0;
long count = Math.round(elapsed / (double) mVSyncIntervalNanos); long vSyncIntervalNanos = elapsed / mVSyncCount;
if (count < MIN_FRAME_COUNT) return; if (vSyncIntervalNanos < mMinVSyncIntervalNanos) {
long vSyncIntervalNanos = elapsed / count; // We may run slow, but we should never run fast. If the VSync interval is too
if (vSyncIntervalNanos > mMaxVSyncIntervalNanos // low, something is very wrong.
|| vSyncIntervalNanos < mMinVSyncIntervalNanos) {
// This algorithm for computing VSync becomes unstable if it drifts too far from
// the real VSync, which shouldn't happen in practice. If this assert is getting
// hit, something has gone very wrong, but we should probably do something
// reasonable for release builds.
Log.v(TAG, "Error computing VSync interval. Resetting."); Log.v(TAG, "Error computing VSync interval. Resetting.");
assert false; assert false;
vSyncIntervalNanos = mReportedVSyncNanos; vSyncIntervalNanos = mReportedVSyncNanos;
...@@ -535,8 +533,7 @@ public class VrShellDelegate implements ApplicationStatus.ActivityStateListener, ...@@ -535,8 +533,7 @@ public class VrShellDelegate implements ApplicationStatus.ActivityStateListener,
.getDefaultDisplay(); .getDefaultDisplay();
mReportedVSyncNanos = (long) ((1.0d / display.getRefreshRate()) * NANOS_PER_SECOND); mReportedVSyncNanos = (long) ((1.0d / display.getRefreshRate()) * NANOS_PER_SECOND);
mVSyncIntervalNanos = mReportedVSyncNanos; mVSyncIntervalNanos = mReportedVSyncNanos;
mMaxVSyncIntervalNanos = (long) (VSYNC_DRIFT_THRESHOLD * mReportedVSyncNanos); mMinVSyncIntervalNanos = (long) (mReportedVSyncNanos / MIN_VSYNC_INTERVAL_THRESHOLD);
mMinVSyncIntervalNanos = (long) (mReportedVSyncNanos / VSYNC_DRIFT_THRESHOLD);
} }
void updateVSyncInterval(long frameTimeNanos, long vSyncIntervalNanos) { void updateVSyncInterval(long frameTimeNanos, long vSyncIntervalNanos) {
...@@ -548,6 +545,7 @@ public class VrShellDelegate implements ApplicationStatus.ActivityStateListener, ...@@ -548,6 +545,7 @@ public class VrShellDelegate implements ApplicationStatus.ActivityStateListener,
} }
mVSyncIntervalMicros = vSyncIntervalMicros; mVSyncIntervalMicros = vSyncIntervalMicros;
mVSyncTimebaseNanos = frameTimeNanos; mVSyncTimebaseNanos = frameTimeNanos;
mVSyncCount = 0;
nativeUpdateVSyncInterval( nativeUpdateVSyncInterval(
mNativeVrShellDelegate, mVSyncTimebaseNanos, mVSyncIntervalMicros); mNativeVrShellDelegate, mVSyncTimebaseNanos, mVSyncIntervalMicros);
...@@ -558,6 +556,8 @@ public class VrShellDelegate implements ApplicationStatus.ActivityStateListener, ...@@ -558,6 +556,8 @@ public class VrShellDelegate implements ApplicationStatus.ActivityStateListener,
} }
public void resume() { public void resume() {
mVSyncTimebaseNanos = 0;
mVSyncCount = 0;
Choreographer.getInstance().postFrameCallback(mCallback); Choreographer.getInstance().postFrameCallback(mCallback);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment