Hi everyone, I've been thinking about ways that Servo's architecture can result in user experience improvements in common Web patterns today. One particularly relevant thing that's becoming clear is that Web pages often animate CSS properties that require reflows in current Web browsers. Google has a document that investigates performance issues in some high-profile sites [1], and the very first one shows that CNet's slide-out animation is slow for this reason. I've also anecdotally seen this on sites ranging from Twitter to Google Maps. So far, the approach has been to evangelize use of CSS transforms instead [2], but that seems to me to be a less scalable approach than simply making these transitions fast. It's natural, after all, for Web developers to want to use the same set of properties for animation that they do for layout.
Optimizing animations that require reflows to be as fast as animations that can run on the compositor is not easy in current browser engine architectures for a variety of reasons. But it seems to me that there are several pieces, some currently unique to Servo, that would allow us to get to this world: 1. *Do layout off the DOM/script thread.* One of the biggest reasons why compositable animations are fast is that they can run concurrently with JavaScript and everything else on the main thread. This is difficult to fix in major browser engines, because style recalculation and layout fundamentally have to access the DOM (and vice versa—the DOM accesses layout data structures). But this is not true in Servo: layout runs off the main thread and the DOM accesses layout data structures only through message passing (conceptually anyway; there are fast paths that allow message-passing-free trips when safe to do so). So this one is already solved in our architecture. 2. *Avoid going through style recalculation for transitions.* Style recalculation (including CSS selector matching and layout object construction) fundamentally has to access the DOM. But there is no need to actually do this to update style objects for CSS transitions. My work-in-progress transitions branch implements a "back door" that allows style to be updated without going through style recalculation if we know in advance which properties are to be updated. Coupled with (1) above, this allows these transitions to be fully dissociated from the main thread. 3. *Use display-list-based invalidation.* DLBI allows us to detect that the contents of a layer did not change and therefore avoid painting it entirely. This is important when animating properties like "top", "left", "margin", and "padding": often these properties cause elements to move around on the page without their contents changing, but it is tricky to figure this out in advance. However, with DLBI, we can simply perform the display list construction and then determine after the fact that the layer contents did not change. This allows us to determine with precision whether it is possible to skip the rasterization/painting step entirely. The fact that rasterization/painting does not occur is an important reason why compositable animations are fast today. Servo does not currently implement DLBI, but the infrastructure is there to support it. 4. *Support multiple layers per stacking context.* Many, perhaps most, absolutely-positioned elements that are animated have `z-index: auto` and so don't form a stacking context. In order to avoid repainting when animating such elements, the engine needs to support layerizing elements that aren't part of a stacking context. For each frame, the easiest way to do this is to rebuild the display list, flatten it, and then divide up the now-linearized display items into layers. The tricky thing here is to determine when to break up a stacking context's display list into multiple layers and when not to; ideally the heuristics should be as simple as possible in order to keep the code maintainable and to make the performance characteristics easy to understand for Web authors. Servo does not currently support this feature, but it will be needed in order to properly render canvas without readback. It should not be terribly difficult to implement; the most difficult part will be figuring out the heuristics. 5. *Reduce display list building overhead.* Right now, Servo rebuilds display lists for the entire document and all stacking contexts, regardless of how big the document is and whether the stacking contexts have changed. This is obviously suboptimal. There is a lot of stuff we can do here, from supporting a displayport and only building display lists within that displayport all the way up to tile-based incremental DL building [3]. It's not clear to me how much we need to do here to hit that magic 60 FPS number on most Web sites. Altogether, when this work is complete, I see no reason why 60 FPS transitions should not be possible for all reasonable properties. There will still be some pathological transitions that will be slow because of layout and/or repainting overhead, but I suspect they will be rare, and layout at least is really fast in Servo thanks to parallelism and overall code cleanliness. One remaining issue is how to deal with jQuery-style animations that are done with setTimeout(). They have to contend with everything else on the DOM/script thread to avoid breaking the HTML/JavaScript event loop semantics. I've brainstormed ideas for doing some sort of fair scheduling for events on the main thread to try to give animations priority wherever possible, but anything like this still has to deal with the run-to-completion for event handlers that hog the CPU. I'm open to ideas here. Thoughts on any of this? Patrick [1]: https://docs.google.com/document/d/1K-mKOqiUiSjgZTEscBLjtjd6E67oiK8H2ztOiq5tigk/pub [2]: http://www.html5rocks.com/en/tutorials/speed/high-performance-animations/ [3]: https://github.com/servo/servo/issues/3852 _______________________________________________ dev-servo mailing list dev-servo@lists.mozilla.org https://lists.mozilla.org/listinfo/dev-servo