[webkit-dev] Enable REQUEST_ANIMATION_FRAME on all ports? (was Re: ENABLE flag cleanup strawman proposal)

Chris Marrin cmarrin at apple.com
Wed Sep 28 12:01:39 PDT 2011

On Sep 27, 2011, at 8:57 PM, James Robinson wrote:

> ...With that said, I agree with you that there will still be a visual glitch in the current implementation. But what's actually happening is that the timestamp we're sending to rAF is wrong. We're sending current time. Depending on when rAF fires relative to the display refresh, the timestamp might be as much as 16ms behind the time the frame is actually seen. If you're basing motion on this timestamp, there will be an occasion when one frame will have a timestamp that is very close to the display time and the next will have a timestamp that is 15ms or so behind. That's why the glitch is happening.
> I'm assuming in this example that the script changing the position of the bird to match the timestamp parameter passed in. You are correct in saying that changing the timestamp parameter to reflect the next display time would get rid of the visual glitch in this example.  In that case the behavior between frames 8 and 10 would be:
> time (millis) : action
> 120: rAF fired with timestamp 133 1/3
> 133 1/3: frame 8 produced
> 135: rAF fired with timestamp 150
> 150: rAF fired with timestamp 150
> 150 0/3: frame 9 produced
> 165: rAF fired with timestamp 166 2/3
> 166 2/3: frame 10 produced
> The problem here is that in the real world, frames aren't infinitely cheap to produce and so attempting to run the rAF callback twice between frames 8 and 9 is just as likely to produce a rendering glitch as the problem in the original example - even though the timestamp is correct.  In order to keep the animation running smoothly here it's necessary to keep the timestamp and the scheduling in sync with the actual display rate.

Right. That's why I'm doing an implementation which uses CVDisplayLink, which is synchronized with the display.

> ...
> I think the issue of supplying rAF with accurate timestamps is independent of whatever feedback mechanism an implementation uses to do the throttling. I'm sure those heuristics will improve over time. But the first step is to supply rAF with an accurate timestamp. I've opened https://bugs.webkit.org/show_bug.cgi?id=68911 for this. My intention is to create a call, similar to scheduleAnimation() but which simply asks platform specific code for a time estimate of when the next frame will be visible. That can not only be used as the timestamp sent to rAF, but as the basis for when the next call to rAF is made. That should avoid any excessive calls to rAF.
> That sounds like a good start, but I don't really think it will be sufficient.  How will the WebKit layer know when the next frame will be visible?  There are many considerations in frame scheduling in addition to the screen's display rate.  I think you'll need to end up duplicating all of the WebKit-specific frame scheduling logic into the WebCore implementation, or just be wrong most of the time.

I'm not sure what logic you're talking about. But CVDisplayLink is synchronized with the display, so it should (hopefully) be sufficient.

> For Mac, I plan to look into adding a displayLink thread which will maintain a timestamp value tied to refresh. I didn't try using a displayLink at first because I initially thought I'd use it to actually drive the firing of the callback, which would have been complicated and require a lot of communication between the threads. Just having the displayLink maintain a timestamp means I just need to provide thread safe access to that value. Hopefully that will keep overhead low but will achieve the synchronization goal.
> Getting the refresh interval is only the first step.  In the contention case (which is the really interesting one) just knowing the refresh time of the display does not give you enough insight into when to pump the animation in order to make the next frame.

There is no way to know (no matter what technique you use) if you'll make it to the display "on time". Even if you start your rendering a full 16ms before the next frame is to be displayed AND you're supplied with timestamp of when that frame will be displayed AND your rendering code takes much less than 16ms to complete, you still might not make it. Javascript garbage collection, layout, an image getting loaded or any one of a number of other things inside the app could take enough time that you miss the window. And other apps could get a time slice and prevent you from making it as well.

Desktop OS's are not real-time systems, so the best you can do is to give yourself the best chance of success. That means getting as much time as possible (~16ms) to render before the frame appears and finishing your rendering as quickly as possible (probably at least a couple of ms before the frame is to appear).

Regardless of your concerns, today's completely unsynchronized Timer based rAF implementation looks pretty good. It mostly achieves the above criteria. It just has a slightly visible glitch every once in a while. A synchronized implementation, like in Chrome and soon in WebKit on Mac, will do a better job. Sometimes, when the system and the page are fairly quiescent, they will be nearly perfect. It still remains to be proven, but I believe my CVDisplayLink implementation will be as smooth as the current Chrome implementation.

> ...I don't think you need to worry. The current REQUEST_ANIMATION_FRAME_TIMER implementation does what it was intended to do - provide a platform independent implementation of requestAnimationFrame. It provides callbacks at an even rate and avoids excessive CPU consumption. I don't think the occasional animation glitch is a major flaw. It's just an issue that needs to be addressed on a platform specific basis to improve animation quality.
> Sure, but the only way to achieve that improvement is to replace the WebCore-timer based system completely.

I really don't see why. It you use a Timer and set its timeout based on a timebase that is in sync with display refresh, it should be as good as any other possible implementation. Essentially you're merely using the Timer as the trigger for the callback. The timing is coming from display refresh. How is that not a sufficient implementation?

cmarrin at apple.com

More information about the webkit-dev mailing list