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

Reply via email to