Pages that repeatedly call offsetWidth then change style will force a lot of unnecessary compositing updates. We should avoid them, and figure out a way to only update compositing layers before painting.
Maybe we could use the rAF mechanism here too
One difficulty design-wise is that currently WebCore doesn't generally know if it's doing layout because the host wants to make a frame or if it's doing layout for some other reason (like JS wanted it to or the host wants it to do layout to query some values). If we knew that in FrameView::layout then we could only update the compositing tree when it was a layout-because-it's-make-a-frame-time.
We could use the rAF mechanism since it's (hopefully) tied in to the host's "I want to make a frame now" scheduling mechanism.
I don't think knowing the "reason for layout" in FrameView::layout is enough; you need to know if this is the last layout you'll get before painting happens.
We also have the "sync compositing layer" stuff that is based on a run loop observer but also fires before painting.
Just saw this when scrolling macnn.com, via JS calling pageYOffset.
Lots of time in
absBounds = layer->renderer()->localToAbsoluteQuad(FloatRect(layer->localBoundingBox())).enclosingBoundingBox();
Site that would benefit from this: http://www.milwaukeepolicenews.com/
(In reply to comment #6)
> Site that would benefit from this: http://www.milwaukeepolicenews.com/
Can we add a platform hook that the embedder has to call when they wanna make a frame? I imagine it'd tie to the run loop observer for you, and I've have to hook it in somewhere for chromium (WebKit::WebViewImpl::layout() would be a good approximation). I don't know where to put it for other ports.
I think we should enhance RunLoop for this kind of thing. We would just need a callback for things that want to run near the end of the runloop (after timers, before layer committing).
The RunLoop can spin many many times in between frames (hopefully each operation isn't blocking for 16ms), so I think just tracking that by itself will still produce a lot of unnecessary uCL() calls.
Maybe we should leverage requestAnimationFrame underpinnings then. I already do that for TiledLayer flushing.
We can't just not update compositing layers, because otherwise GraphicsLayers will be left pointing at RenderLayerBackings which might have gone away.
*** Bug 118555 has been marked as a duplicate of this bug. ***
Would it hurt compositing too much to make updating the compositing layers a completely separate pass from layout?
(In reply to comment #13)
> Would it hurt compositing too much to make updating the compositing layers a
> completely separate pass from layout?
No, that would be ideal. The problem is that we can't easily disassociate compositing layer updates from layout without losing repaints. If we stored repaints differently this would be easier to do.
So we need an in-WebKit data structure for tracking repaints and then we’d communicate any repainting to the OS only after updating compositing layers.
(In reply to comment #15)
> So we need an in-WebKit data structure for tracking repaints
We have this already (we accumulate dirty rects in GraphicsLayers). The problems are:
1. we dirty during layout, and dirtying assumes that you can find the relevant repaintContainer (which is a compositing layer) and compute a dirty rect relative to it.
2. RenderLayers cache repaint rects, which will also go stale if their repaint container changes because of compositing updates.
So we need a data structure that hangs off the render tree that tracks repaints, and can track them sensibly across multiple layouts, in a compositing-independent way.
I hacked this up and it mostly worked, but some tests fail because of tree statefulness.
Created attachment 377678 [details]