Commit d2a1c7c4 authored by ojan@chromium.org's avatar ojan@chromium.org

Cache the absolute bounding box rect on RenderLayer.

Set the cache dirty in RenderLayer::styleChanged and recompute
the rect during computeCompositingRequirements.

Also, get rid of absoluteBoundingBox from RenderLayer. The only
caller can use the new cached value since it always happens after
computeCompositingRequirements.

The unfortunate thing is that if a RenderLayer is modified, we
need to recompute the absolute bounds for all its descendant layers.

This saves ~3% of the computeCompositingRequirements time on the
tip of tree version of https://github.com/abarth/app-widgets/blob/master/demo.html.

The version checked into the key_silk_cases pageset doesn't show
the perf win because it doesn't have many RenderLayers outside
of the drawer being dragged.

The bigger win will come from the following patch that adds/removes
layers to the RenderGeometryMap lazily. Right now that's 10-20% of
the computeCompositingRequirements time in this demo.

Review URL: https://codereview.chromium.org/208313004

git-svn-id: svn://svn.chromium.org/blink/trunk@169786 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent f37bdd22
......@@ -126,6 +126,7 @@ RenderLayer::RenderLayer(RenderLayerModelObject* renderer, LayerType type)
, m_containsDirtyOverlayScrollbars(false)
, m_canSkipRepaintRectsUpdateOnScroll(renderer->isTableCell())
, m_hasFilterInfo(false)
, m_needsToRecomputeBounds(true)
, m_renderer(renderer)
, m_parent(0)
, m_previous(0)
......@@ -1215,6 +1216,17 @@ RenderLayer* RenderLayer::enclosingFilterLayer(IncludeSelfOrNot includeSelf) con
return 0;
}
void RenderLayer::clearNeedsToRecomputeBounds()
{
m_needsToRecomputeBounds = false;
}
void RenderLayer::setAbsoluteBoundingBox(const IntRect& rect)
{
m_absoluteBoundingBox = rect;
clearNeedsToRecomputeBounds();
}
void RenderLayer::setCompositingReasons(CompositingReasons reasons, CompositingReasons mask)
{
ASSERT(reasons == (reasons & mask));
......@@ -3422,11 +3434,6 @@ LayoutRect RenderLayer::boundingBox(const RenderLayer* ancestorLayer, CalculateL
return result;
}
IntRect RenderLayer::absoluteBoundingBox() const
{
return pixelSnappedIntRect(boundingBox(root()));
}
LayoutRect RenderLayer::calculateLayerBounds(const RenderLayer* ancestorLayer, const LayoutPoint* offsetFromRoot, CalculateLayerBoundsFlags flags) const
{
if (!isSelfPaintingLayer())
......@@ -3961,8 +3968,13 @@ void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle* oldStyle
// https://code.google.com/p/chromium/issues/detail?id=343756
DisableCompositingQueryAsserts disabler;
// FIXME: We could avoid doing this ancestor walk by keeping a childNeedsToRecomputeBounds bit
// and using that along with needsToRecomputeBounds to set this bit in a later layer tree walk
// e.g. during assignLayersToBackings or computeCompositingRequirements.
if (RenderLayer* compositingLayer = enclosingCompositingLayer())
compositingLayer->compositedLayerMapping()->setNeedsGeometryUpdate();
// FIXME: We only need to set this if something changed that can change our absolute bounding rect.
m_needsToRecomputeBounds = true;
const RenderStyle* newStyle = renderer()->style();
......
......@@ -298,10 +298,6 @@ public:
// Bounding box relative to some ancestor layer. Pass offsetFromRoot if known.
LayoutRect boundingBox(const RenderLayer* rootLayer, CalculateLayerBoundsFlags = 0, const LayoutPoint* offsetFromRoot = 0) const;
// Bounding box in the coordinates of this layer.
LayoutRect localBoundingBox(CalculateLayerBoundsFlags = 0) const;
// Pixel snapped bounding box relative to the root.
IntRect absoluteBoundingBox() const;
// Bounds used for layer overlap testing in RenderLayerCompositor.
LayoutRect overlapBounds() const { return overlapBoundsIncludeChildren() ? calculateLayerBounds(this) : localBoundingBox(); }
......@@ -484,6 +480,10 @@ public:
void clearAncestorDependentPropertyCache();
const IntRect& absoluteBoundingBox() { ASSERT(!m_needsToRecomputeBounds); return m_absoluteBoundingBox; }
void setAbsoluteBoundingBox(const IntRect&);
void clearNeedsToRecomputeBounds();
bool needsToRecomputeBounds() { return m_needsToRecomputeBounds; }
private:
class AncestorDependentPropertyCache {
......@@ -510,6 +510,9 @@ private:
void ensureAncestorDependentPropertyCache() const;
// Bounding box in the coordinates of this layer.
LayoutRect localBoundingBox(CalculateLayerBoundsFlags = 0) const;
bool hasOverflowControls() const;
void setIsUnclippedDescendant(bool isUnclippedDescendant) { m_isUnclippedDescendant = isUnclippedDescendant; }
......@@ -710,6 +713,7 @@ private:
const unsigned m_canSkipRepaintRectsUpdateOnScroll : 1;
unsigned m_hasFilterInfo : 1;
unsigned m_needsToRecomputeBounds : 1;
RenderLayerModelObject* m_renderer;
......@@ -732,6 +736,8 @@ private:
LayoutUnit m_staticInlinePosition;
LayoutUnit m_staticBlockPosition;
IntRect m_absoluteBoundingBox;
OwnPtr<TransformationMatrix> m_transform;
// Pointer to the enclosing RenderLayer that caused us to be paginated. It is 0 if we are not paginated.
......
......@@ -163,9 +163,10 @@ private:
};
struct CompositingRecursionData {
CompositingRecursionData(RenderLayer* compAncestor, RenderLayer* mostRecentCompositedLayer, bool testOverlap)
CompositingRecursionData(RenderLayer* compAncestor, RenderLayer* mostRecentCompositedLayer, RenderLayerCompositor::BoundsUpdateType boundsUpdateType, bool testOverlap)
: m_compositingAncestor(compAncestor)
, m_mostRecentCompositedLayer(mostRecentCompositedLayer)
, m_recomputeLayerBoundsUpdateType(boundsUpdateType)
, m_subtreeIsCompositing(false)
, m_hasUnisolatedCompositedBlendingDescendant(false)
, m_testingOverlap(testOverlap)
......@@ -178,6 +179,7 @@ struct CompositingRecursionData {
CompositingRecursionData(const CompositingRecursionData& other)
: m_compositingAncestor(other.m_compositingAncestor)
, m_mostRecentCompositedLayer(other.m_mostRecentCompositedLayer)
, m_recomputeLayerBoundsUpdateType(other.m_recomputeLayerBoundsUpdateType)
, m_subtreeIsCompositing(other.m_subtreeIsCompositing)
, m_hasUnisolatedCompositedBlendingDescendant(other.m_hasUnisolatedCompositedBlendingDescendant)
, m_testingOverlap(other.m_testingOverlap)
......@@ -189,6 +191,7 @@ struct CompositingRecursionData {
RenderLayer* m_compositingAncestor;
RenderLayer* m_mostRecentCompositedLayer; // in paint order regardless of hierarchy.
RenderLayerCompositor::BoundsUpdateType m_recomputeLayerBoundsUpdateType;
bool m_subtreeIsCompositing;
bool m_hasUnisolatedCompositedBlendingDescendant;
bool m_testingOverlap;
......@@ -205,6 +208,7 @@ RenderLayerCompositor::RenderLayerCompositor(RenderView& renderView)
, m_needsToRecomputeCompositingRequirements(false)
, m_needsToUpdateLayerTreeGeometry(false)
, m_pendingUpdateType(GraphicsLayerUpdater::DoNotForceUpdate)
, m_recomputeLayerBoundsUpdateType(DoNotForceUpdate)
, m_compositing(false)
, m_compositingLayersNeedRebuild(false)
, m_forceCompositingMode(false)
......@@ -369,17 +373,23 @@ void RenderLayerCompositor::setNeedsCompositingUpdate(CompositingUpdateType upda
m_needsToRecomputeCompositingRequirements = true;
// FIXME: Ideally we'd be smarter about tracking dirtiness and wouldn't need a ForceUpdate here.
m_pendingUpdateType = GraphicsLayerUpdater::ForceUpdate;
// FIXME: Ideally we'd be smarter about tracking dirtiness and wouldn't need a ForceUpdate here.
m_recomputeLayerBoundsUpdateType = ForceUpdate;
break;
case CompositingUpdateOnScroll:
m_needsToRecomputeCompositingRequirements = true; // Overlap can change with scrolling, so need to check for hierarchy updates.
m_needsToUpdateLayerTreeGeometry = true;
// FIXME: Ideally we'd be smarter about tracking dirtiness and wouldn't need a ForceUpdate here.
m_pendingUpdateType = GraphicsLayerUpdater::ForceUpdate;
// FIXME: Ideally we'd be smarter about tracking dirtiness and wouldn't need a ForceUpdate here.
m_recomputeLayerBoundsUpdateType = ForceUpdate;
break;
case CompositingUpdateOnCompositedScroll:
m_needsToUpdateLayerTreeGeometry = true;
// FIXME: Ideally we'd be smarter about tracking dirtiness and wouldn't need a ForceUpdate here.
m_pendingUpdateType = GraphicsLayerUpdater::ForceUpdate;
// FIXME: Ideally we'd be smarter about tracking dirtiness and wouldn't need a ForceUpdate here.
m_recomputeLayerBoundsUpdateType = ForceUpdate;
break;
case CompositingUpdateAfterCanvasContextChange:
m_needsToUpdateLayerTreeGeometry = true;
......@@ -442,6 +452,14 @@ bool RenderLayerCompositor::hasUnresolvedDirtyBits()
return m_needsToRecomputeCompositingRequirements || m_compositingLayersNeedRebuild || m_needsToUpdateLayerTreeGeometry || m_needsUpdateCompositingRequirementsState || m_pendingUpdateType != GraphicsLayerUpdater::DoNotForceUpdate;
}
static void assertNeedsRecomputeBoundsBitsCleared(RenderLayer* updateRoot)
{
// We don't do overlap testing on the root layer, so we never compute its absolute bounding box.
ASSERT(updateRoot->isRootLayer() || !updateRoot->needsToRecomputeBounds());
for (RenderLayer* child = updateRoot->firstChild(); child; child = child->nextSibling())
assertNeedsRecomputeBoundsBitsCleared(child);
}
void RenderLayerCompositor::updateCompositingLayersInternal()
{
if (isMainFrame() && m_renderView.frameView())
......@@ -474,7 +492,8 @@ void RenderLayerCompositor::updateCompositingLayersInternal()
if (needCompositingRequirementsUpdate) {
// Go through the layers in presentation order, so that we can compute which RenderLayers need compositing layers.
// FIXME: we could maybe do this and the hierarchy udpate in one pass, but the parenting logic would be more complex.
CompositingRecursionData recursionData(updateRoot, 0, true);
CompositingRecursionData recursionData(updateRoot, 0, m_recomputeLayerBoundsUpdateType, true);
m_recomputeLayerBoundsUpdateType = DoNotForceUpdate;
bool layersChanged = false;
bool saw3DTransform = false;
{
......@@ -488,6 +507,9 @@ void RenderLayerCompositor::updateCompositingLayersInternal()
Vector<RenderLayer*> unclippedDescendants;
IntRect absoluteDecendantBoundingBox;
computeCompositingRequirements(0, updateRoot, &overlapTestRequestMap, recursionData, saw3DTransform, unclippedDescendants, absoluteDecendantBoundingBox);
#if !ASSERT_DISABLED
assertNeedsRecomputeBoundsBitsCleared(updateRoot);
#endif
}
{
......@@ -893,7 +915,7 @@ void RenderLayerCompositor::layerWillBeRemoved(RenderLayer* parent, RenderLayer*
setCompositingLayersNeedRebuild();
}
void RenderLayerCompositor::addToOverlapMap(OverlapMap& overlapMap, RenderLayer* layer, IntRect& layerBounds)
void RenderLayerCompositor::addToOverlapMap(OverlapMap& overlapMap, RenderLayer* layer, const IntRect& layerBounds)
{
if (layer->isRootLayer())
return;
......@@ -971,13 +993,21 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* ancestor
IntRect absBounds;
if (overlapMap && !layer->isRootLayer()) {
absBounds = enclosingIntRect(overlapMap->geometryMap().absoluteRect(layer->overlapBounds()));
if (currentRecursionData.m_recomputeLayerBoundsUpdateType == ForceUpdate || layer->needsToRecomputeBounds()) {
// FIXME: If the absolute bounds didn't change, then we don't need to ForceUpdate descendant RenderLayers.
currentRecursionData.m_recomputeLayerBoundsUpdateType = ForceUpdate;
absBounds = enclosingIntRect(overlapMap->geometryMap().absoluteRect(layer->overlapBounds()));
layer->setAbsoluteBoundingBox(absBounds);
} else {
absBounds = layer->absoluteBoundingBox();
}
// Setting the absBounds to 1x1 instead of 0x0 makes very little sense,
// but removing this code will make JSGameBench sad.
// See https://codereview.chromium.org/13912020/
if (absBounds.isEmpty())
absBounds.setSize(IntSize(1, 1));
}
absoluteDecendantBoundingBox = absBounds;
if (overlapMap && currentRecursionData.m_testingOverlap && !requiresCompositingOrSquashing(directReasons))
......@@ -1040,9 +1070,10 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* ancestor
// negative z-index child's bounds to the new overlap context.
if (overlapMap) {
overlapMap->geometryMap().pushMappingsToAncestor(curNode->layer(), layer);
IntRect childAbsBounds = enclosingIntRect(overlapMap->geometryMap().absoluteRect(curNode->layer()->overlapBounds()));
// The above call to computeCompositinRequirements will have already updated this layer's absolute bounding box.
overlapMap->beginNewOverlapTestingContext();
addToOverlapMap(*overlapMap, curNode->layer(), childAbsBounds);
ASSERT(!curNode->layer()->needsToRecomputeBounds());
addToOverlapMap(*overlapMap, curNode->layer(), curNode->layer()->absoluteBoundingBox());
overlapMap->finishCurrentOverlapTestingContext();
overlapMap->geometryMap().popMappingsToAncestor(layer);
}
......@@ -1117,8 +1148,10 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* ancestor
// If the original layer is composited, the reflection needs to be, too.
if (layer->reflectionInfo()) {
// FIXME: Shouldn't we call computeCompositingRequirements to handle a reflection overlapping with another renderer?
RenderLayer* reflectionLayer = layer->reflectionInfo()->reflectionLayer();
reflectionLayer->clearNeedsToRecomputeBounds();
CompositingReasons reflectionCompositingReason = willBeCompositedOrSquashed ? CompositingReasonReflectionOfCompositedParent : CompositingReasonNone;
layer->reflectionInfo()->reflectionLayer()->setCompositingReasons(layer->reflectionInfo()->reflectionLayer()->compositingReasons() | reflectionCompositingReason);
reflectionLayer->setCompositingReasons(reflectionLayer->compositingReasons() | reflectionCompositingReason);
}
// Subsequent layers in the parent's stacking context may also need to composite.
......
......@@ -62,6 +62,11 @@ enum CompositingUpdateType {
class RenderLayerCompositor FINAL : public GraphicsLayerClient {
WTF_MAKE_FAST_ALLOCATED;
public:
enum BoundsUpdateType {
DoNotForceUpdate,
ForceUpdate,
};
// FIXME: This constructor should take a reference.
explicit RenderLayerCompositor(RenderView&);
virtual ~RenderLayerCompositor();
......@@ -272,7 +277,7 @@ private:
void recursiveRepaintLayer(RenderLayer*);
void addToOverlapMap(OverlapMap&, RenderLayer*, IntRect& layerBounds);
void addToOverlapMap(OverlapMap&, RenderLayer*, const IntRect& layerBounds);
// Forces an update for all frames of frame tree recursively. Used only when the mainFrame compositor is ready to
// finish all deferred work.
......@@ -349,6 +354,8 @@ private:
bool m_needsToUpdateLayerTreeGeometry;
GraphicsLayerUpdater::UpdateType m_pendingUpdateType;
RenderLayerCompositor::BoundsUpdateType m_recomputeLayerBoundsUpdateType;
bool m_compositing;
bool m_compositingLayersNeedRebuild;
bool m_forceCompositingMode;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment