Hi everyone,
My initial work on the implementation of `opacity`, as well as
discussions with Martin Robinson last week, have begun to make me wonder
whether we should modify Servo's layerization/display list model
somewhat. Currently, the output of layout (i.e. what layout sends to the
painting thread) is a tree† of `RenderLayer`s with a flat list of
`DisplayItem`s for each such layer. Every `RenderLayer` corresponds to a
tiled hardware surface. For each fragment, layout decides whether it
should get a layer or whether it should just contribute display items to
its parent.
The simplicity of this scheme is great, but there are a number of issues
we've run into:
1. It's not clear how to represent `transform`, especially nested ones
combined with complex clipping regions (like those generated by
`border-radius`), with a flat list of display items. We would either
need each set of display items to carry a stack of transform matrices
and clips (like Skia's `MCStack`) or to make the display list into a
tree, causing annoyances similar to those that Gecko's old
`nsDisplayClip` (and Servo's `ClipDisplayItem`) caused.
2. `DisplayList::flatten`, which shuffles display items into the proper
order to form a new stacking context, is surprisingly high in the
profile, accounting for as much as 20% of display list construction in
some cases.
3. Having layout choose whether each item gets a layer is annoying due
to having to scatter "should I layerize this?" logic throughout layout.
It was manageable when `position: fixed` and the root element were the
only things that could make layers, but with `opacity` on the scene
every fragment can potentially make a layer (and you clearly don't want
to make hardware layers for every element with `opacity` < 1, so we
would need both code paths).
I came up with a potential solution: Instead of having layout send a
tree of render layers, have it send a tree of *stacking contexts*. A
stacking context is a set of display lists (one for each "layer" defined
in CSS 2.1 Appendix E), plus a z-index and a set of child stacking
contexts. The painting thread makes the decision as to whether each
stacking context gets a hardware layer; it may want to layerize some and
not others. Layout does not have to care whether each stacking context
is layerized in the accelerated compositing sense or not.
This provides a solution for problems (1)-(3). For problem (1),
`transform` always creates a stacking context, so we neatly avoid having
to have a stack of clip regions and transform matrices per display item:
the tree of stacking contexts implicitly defines that stack. We solve
problem (2) by avoiding having to explicitly shuffle display items
around; for each stacking context, the painting thread just paints the
lists in the right order, which both reduces the work to be done and
moves the remaining work from the layout thread to the painting thread.
And problem (3) is solved because layout no longer cares about hardware
layerization; it's all stacking contexts as far as layout is concerned.
(There is still the annoyance that `opacity` < 1 always creates a new
stacking context, but that is complexity we have to buy into no matter
what.)
Note that this does *not* solve the problem of not being able to
layerize things that are not true stacking contexts (which is an issue
that also applies to Blink and WebKit). However, I can see ways in which
it could be extended to a more `FrameLayerBuilder`-like approach without
rewriting all our painting code if it becomes important to do so in the
future.
It's also not immediately clear to me how this integrates with the
per-tile display list construction stuff that we want to do, but I don't
think it's an insurmountable problem.
Thoughts?
Patrick
† This is actually not true in the current implementation; rather
RenderLayers are a flat list, with the first layer in the list
representing the "root layer". But this is obviously wrong and we are
working on changing it.
_______________________________________________
dev-servo mailing list
dev-servo@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-servo