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

Dimitri Glazkov dglazkov at chromium.org
Tue Sep 27 08:57:55 PDT 2011

James, this is a crazy cool mail. I found it full of TILs and think
its guts totally should be on our blog. Bonus points: pictures.


On Mon, Sep 26, 2011 at 9:48 PM, James Robinson <jamesr at google.com> wrote:
> On Sun, Sep 25, 2011 at 6:52 PM, Darin Adler <darin at apple.com> wrote:
>> On Sep 25, 2011, at 12:20 AM, James Robinson wrote:
>> > The TIMER based support for RAF is very new (only a few weeks old) and
>> > still has several major bugs. I'd suggest letting it bake for a bit before
>> > considering turning it on for all ports.
>> Got it.
>> > Fundamentally I don't think this feature can be implemented reasonably
>> > well with just timers, so port maintainers should take a really careful look
>> > at the level of support they want to have for this feature when deciding if
>> > they want to support it.
>> This may contradict the recommendation above. If the timer-based version
>> is too low quality then maybe we shouldn’t put ports in the position of
>> shipping with a substandard implementation rather than simply having the
>> feature omitted.
> Perhaps if I expand on my concerns a bit it'll be clearer what the right
> option is.
> The goal of requestAnimationFrame is to allow web authors to have
> high-quality script-driven animations.  To use a concrete example, when
> playing angry birds (http://chrome.angrybirds.com/) and flinging a bird
> across the terrain, the RAF-based animation should move the bird at a
> uniform rate across the screen at the same framerate as the physical display
> without hitches or interruptions.  An additional goal is that we shouldn't
> do any unnecessary work for frames that do not show up on screen, although
> it's generally necessary to do this in order to satisfy the first goal as
> I'll show below.  There are two main things that you need in order to
> achieve this that are difficult or impossible to do with a WebCore Timer: a
> reliable display-rate aligned time source, and a source of feedback from the
> underlying display mechanism.
> The first is easiest to think about with an example.  When the angry bird
> mentioned above is flying across the screen, the user should experience the
> bird advancing by the same amount every time their display's update
> refreshes.  Let's assume a 60Hz display and a 15ms timer (as the
> current REQUEST_ANIMATION_FRAME_TIMER code uses), and furthermore assume
> (somewhat optimistically) that every frame takes 0ms to process in
> javascript and 0ms to display.  The screen will update at the following
> times (in milliseconds): 0, 16 2/3, 33 1/3, 50, 66 2/3, 83 1/3, 100, etc.
>  The visual X position of the bird on the display is directly proportional
> to the time elapsed when the rAF handler runs, since it's interpolating the
> bird's position, and the rAF handler will run at times 0, 15, 30, 45, 60,
> etc.  We can thus determine the visual X position of the bird for each
> frame:
> Frame 0, time 0ms, position: 0, delta from last frame:
> Frame 1, time 16 2/3ms, position: 15, delta from last frame: 15
> Frame 2, time 33 1/3ms, position: 30, delta from last frame: 15
> Frame 3, time 50 0/3 ms, position: 45, delta from last frame: 15
> Frame 4, time 66 2/3 ms, position: 60, delta from last frame: 15
> Frame 5, time 83 1/3 ms, position: 75, delta from last frame: 15
> Frame 6, time 100 0/0 ms, position: 90, delta from last frame: 15
> Frame 7, time 116 2/3ms, position: 105, delta from last frame: 15
> Frame 8, time 133 1/3ms, position: 120, delta from last frame: 15
> Frame 9, time 150 0/3 ms, position: 150, delta from last frame: 30 (!)
> Frame 10, time 166 2/3 ms, position: 165, delta from last frame: 15
> Frame 11, time 183 1/3 ms, position: 180, delta from last frame: 15
> Frame 12, time 200 0/0 ms, position: 195, delta from last frame: 15
> What happened at frame 9?  Instead of advancing by 15 milliseconds worth,
> the bird jumped forward by twice the normal amount.  Why?  We ran the rAF
> callback twice between frames 8 and 9 - once at 135ms and once at 150ms.
>  What's actually going on here is we're accumulating a small amount of drift
> on every frame (1.66666... milliseconds, to be precision) between when the
> display is refreshing and when the callbacks are being invoked.  This has to
> catch up sometime so we end up with a beat pattern every (16 2/3) / abs(16
> 2/3 - 15) = 10 frames.  The same thing happens with a perfect 16ms timer
> every 25 frames, or with a perfect 17ms timer every 50 frames.  Even a very
> close timer will produce these regular beat patterns and as it turns out the
> human eye is incredibly good at picking out and getting annoyed by these
> effects in an otherwise smooth animation.
> For this reason, you really need a precise time source that is tied in to
> the actual display's refresh rate.  Not all displays are exactly 60Hz - at
> smaller form factors 50 or even 55hz displays are not completely unheard of.
>  Additionally the normal clock APIs aren't always precise enough to stay in
> sync with the actual display - particularly on windows it's really hard to
> find a clock that doesn't drift around all over the place.
> The above analysis assumes that all calls are infinitely fast and there's no
> real contention for system resources.  In practice, though, this is rarely
> the case.  It's not uncommon that the system will temporarily get overloaded
> and has to make tradeoffs between maintaining a high framerate and remaining
> responsive to user input.  In Chromium, we have some logic to ensure that we
> load balance between handling input events and painting to ensure that
> processing one type doesn't completely starve the other.  In a multi-process
> environment, such as WebKit2 or Chromium, there needs to be coordination
> between the two processes in the non-composited path in order to paint a
> bitmap and get it onscreen.  If this logic is all operating completely
> independently from the rAF scheduling then it's very easy to end up
> triggering callbacks at a time when the browser can't produce a frame
> anyway, or painting without invoking the rAF callbacks even if they should
> be invoked.  A related issue is what to do when the rAF callbacks themselves
> cause us to be unable to hit our target framerate - for example by
> invalidating some portion of the page that is very expensive to repaint.  In
> that case, the ideal behavior is to throttle down the rAF callback rate to
> what we can sustain, which requires some feedback from the rest of the
> graphics stack.
> Architecturally I think that WebCore is the wrong place to address these
> issues.  WebCore is responsible for generating repaint invalidations and
> passing them out to the WebKit layer via ChromeClient, and it's responsible
> for painting content when the WebKit layer asks it to.  Otherwise, all of
> the frame scheduling logic that would be relevant to rAF lives outside of
> WebCore in the port-specific layers.  Determining a valid clock source for a
> given graphics stack and deciding when to produce new frames are also highly
> port-specific.
> Note that I don't think that using a timer is necessarily evil in all cases.
>  With some rendering architectures or graphics libraries, it may not be
> possible to produce a better solution.  We still use a timer in chromium in
> our non-composited path, although it is integrated with our frame scheduling
> and back pressure logic.  Additionally a timer is quite easy to code up and
> works "pretty well" most of the time (although you can be sure that your
> pickier users will complain).  There are also some benefits to providing
> this API even without great scheduling - for example a port can throttle the
> rAF callbacks for non-visible content or tabs without the backwards compat
> issues doing the same thing for setTimeout() would have, leading to
> dramatically lower power and resource consumption in some cases.
> I still think it's dangerous to provide this as a default for all ports to
> fall back on, because I worry that if it's there ports will use it without
> considering the issues I mention above.
> - James
>>    -- Darin
> _______________________________________________
> webkit-dev mailing list
> webkit-dev at lists.webkit.org
> http://lists.webkit.org/mailman/listinfo.cgi/webkit-dev

More information about the webkit-dev mailing list