AndroidVSyncHelper may generate multiple OnVSync events
Reported by
artyo...@gmail.com,
Jun 15 2018
|
||||
Issue description
Steps to reproduce the problem:
AndroidVSyncHelper utilizes Android's Choreographer. The method AndroidVSyncHelper.requestVSync calls method Choreographer.postFrameCallback WITHOUT removing the existing one first:
private void requestVSync() {
Choreographer.getInstance().postFrameCallback(mCallback);
}
This causes the same callback to be called multiple times with the same timestamp. You can easily see it if you add logs either into C++ methods AndroidVSyncHelper::OnVSync / VrShellGl::OnVSync or into Java's method AndroidVSyncHelper.doFrame.
What is the expected behavior?
OnVSync callback must be called once per frame.
What went wrong?
All what is necessary to do is to add removeFrameCallback call before calling postFrameCallback:
private void requestVSync() {
// make sure we don't run the same callback twice
Choreographer.getInstance().removeFrameCallback(mCallback);
Choreographer.getInstance().postFrameCallback(mCallback);
}
Did this work before? No
Does this work in other browsers? Yes
Chrome version: master Channel: dev
OS Version: n/a
Flash Version: n/a
,
Jun 15 2018
It is not doubling on rAF callbacks, it is doubling on VrShellGl::OnVSync callbacks. You may get the second call to it, when you call vsync_helper_.RequestVSync in VrShellGl::OnVSync. Seems like it is a matter of timing, so you could be just lucky not seeing it. Or, could be some other logic what prevents from double rAFs, however, it is still possible that you may receive double (or even tripple) OnVSyncs with Choreographer. So, here is the sequence of calls at VSync event: AndroidVSyncHelper.doFrame -> AndroidVSyncHelper::OnVSync -> VrShellGl::OnVSync -> AndroidVSyncHelper.requestVSync -> (instantly, since the previous callback is not removed yet and timing is still good for its call) -> AndroidVSyncHelper.doFrame -> AndroidVSyncHelper::OnVSync -> VrShellGl::OnVSync.
,
Jun 15 2018
Thank you for providing more feedback. Adding the requester to the cc list. For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
,
Jun 15 2018
If what you're saying is correct, then your proposed fix doesn't fix the problem, as when you go to cancel the old callback there is none because it's already fired. What you're describing sounds like it might be a framework bug, that I'm not seeing. Calling AndroidVSyncHelper.requestVSync within AndroidVSyncHelper.doFrame is supposed to request for the next frame.
,
Jun 15 2018
Yes, it is a known "feature" of Android Choreographer. We see it a lot and my way is a correct way to avoid the issue. But it is your call for sure.
,
Jun 15 2018
BTW, the same technique is used in standard Android SDK widget (android-25/android/widget/TextView.java): they also remove the handler inside doFrame.
,
Jun 22 2018
Looking at the android source, https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/view/Choreographer.java the callback is added to mCallbackQueues during postCallbackDelayedInternal, then we synchronously call scheduleFrameLocked if the delay time is <=0. scheduleFrameLocked will call scheduleVsyncLocked if we are on the looper thread, or post a message to run later, and we'll call doScheduleVsync. It looks like we don't actually process the callbacks until the next vsync from the display - android_view_DisplayEventReceiver.cpp for example. For example, doCallbacks in Choreographer appears to be called only when a vsync occurs, and it takes a snapshot of all callbacks that are due at the point it is run, so callbacks that add new callbacks won't have the new callbacks run during the same call of doCallbacks. In short, I don't really see the platform bug, or how our implementation would call the vsync callback multiple times. Potentially there could be bugs when we resume or start the vsync loop. artyom, where you seeing real issues/symptoms of this, or is this a theoretical problem you are concerned with?
,
Jun 25 2018
I have to admit, I've never seen it with Daydream code running (simply because I don't run Daydream code). However, I definitely saw double and even triple VSyncs when I tried to use AndroidVSyncHelper with Oculus code, plus, we know internally about this "feature" of the Choreographer. Maybe it depends on NDK/SDK/Android versions, I don't know.
,
Jun 25 2018
The most likely explanation to me is that your code was unintentionally requesting VSyncs multiple times, and ended up creating multiple VSync loops. However, if you do encounter a device that reproduces this bad Choreographer behaviour, please re-open this issue and let us know. We have DCHECKS in place that should detect this kind of bug and haven't seen it on any devices yet, so I would be surprised if any (even cardboard) VR-supporting devices have this bug.
,
Jul 4
|
||||
►
Sign in to add a comment |
||||
Comment 1 by mthiesse@chromium.org
, Jun 15 2018