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.
:DG< On Mon, Sep 26, 2011 at 9:48 PM, James Robinson <jam...@google.com> wrote: > > > On Sun, Sep 25, 2011 at 6:52 PM, Darin Adler <da...@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@lists.webkit.org > http://lists.webkit.org/mailman/listinfo.cgi/webkit-dev > > _______________________________________________ webkit-dev mailing list webkit-dev@lists.webkit.org http://lists.webkit.org/mailman/listinfo.cgi/webkit-dev