Diff
Modified: trunk/Source/WebCore/ChangeLog (215409 => 215410)
--- trunk/Source/WebCore/ChangeLog 2017-04-17 14:47:04 UTC (rev 215409)
+++ trunk/Source/WebCore/ChangeLog 2017-04-17 15:00:33 UTC (rev 215410)
@@ -1,3 +1,47 @@
+2017-04-17 Antti Koivisto <an...@apple.com>
+
+ GraphicsLayerCA::recursiveCommitChanges should not descend into subtrees without changes
+ https://bugs.webkit.org/show_bug.cgi?id=170851
+
+ Reviewed by Simon Fraser.
+
+ With lots of layers this can be very slow as it always traverses the entire layer tree.
+ For example GIF animations on tumblr.com trigger expensive commits where almost nothing changes.
+
+ This patch adds m_hasDescendantsWithUncommittedChanges bit to GraphicsLayerCA. With this
+ we can avoid descending to branches without changes when committing.
+
+ This patch enabled the optimization on Mac.
+
+ * platform/graphics/ca/GraphicsLayerCA.cpp:
+ (WebCore::GraphicsLayerCA::GraphicsLayerCA::syncPosition):
+
+ Set PositionChanged flag when syncing layer position. This flag does nothing except makes
+ next commit to update the coverage rect (so tiling gets updated).
+
+ (WebCore::GraphicsLayerCA::setVisibleAndCoverageRects):
+
+ Do all setting of m_uncommittedChanges bits via addUncommittedChanges function.
+
+ (WebCore::GraphicsLayerCA::recursiveCommitChanges):
+
+ Bail out if neither the current layer nor any of its descendants have any uncommited changes
+ and none of the ancestors had changes.
+
+ (WebCore::GraphicsLayerCA::commitLayerChangesBeforeSublayers):
+ (WebCore::GraphicsLayerCA::ensureStructuralLayer):
+ (WebCore::GraphicsLayerCA::changeLayerTypeTo):
+ (WebCore::GraphicsLayerCA::addUncommittedChanges):
+
+ Set m_hasDescendantsWithUncommittedChanges bit in ancestors when mutating m_uncommittedChanges.
+
+ (WebCore::GraphicsLayerCA::noteLayerPropertyChanged):
+ * platform/graphics/ca/GraphicsLayerCA.h:
+ (WebCore::RenderLayerCompositor::frameViewDidScroll):
+
+ Tell the scrolling layer that it needs to recompute coverage.
+ This also schedules a layer flush so no need to do that separately.
+
2017-04-16 Chris Dumez <cdu...@apple.com>
CMD+R / CMD+Q is considered as user interaction and beforeunload alert is shown
Modified: trunk/Source/WebCore/platform/graphics/GraphicsLayer.h (215409 => 215410)
--- trunk/Source/WebCore/platform/graphics/GraphicsLayer.h 2017-04-17 14:47:04 UTC (rev 215409)
+++ trunk/Source/WebCore/platform/graphics/GraphicsLayer.h 2017-04-17 15:00:33 UTC (rev 215410)
@@ -525,7 +525,8 @@
// Some compositing systems may do internal batching to synchronize compositing updates
// with updates drawn into the window. These methods flush internal batched state on this layer
// and descendant layers, and this layer only.
- virtual void flushCompositingState(const FloatRect& /* clipRect */) { }
+ enum class FlushScope { Uncommitted, All };
+ virtual void flushCompositingState(const FloatRect& /* clipRect */, FlushScope = FlushScope::All) { }
virtual void flushCompositingStateForThisLayerOnly() { }
// If the exposed rect of this layer changes, returns true if this or descendant layers need a flush,
Modified: trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp (215409 => 215410)
--- trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp 2017-04-17 14:47:04 UTC (rev 215409)
+++ trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp 2017-04-17 15:00:33 UTC (rev 215410)
@@ -581,6 +581,16 @@
noteLayerPropertyChanged(GeometryChanged);
}
+void GraphicsLayerCA::syncPosition(const FloatPoint& point)
+{
+ if (point == m_position)
+ return;
+
+ GraphicsLayer::syncPosition(point);
+ // Ensure future flushes will recompute the coverage rect and update tiling.
+ noteLayerPropertyChanged(PositionChanged, DontScheduleFlush);
+}
+
void GraphicsLayerCA::setAnchorPoint(const FloatPoint3D& point)
{
if (point == m_anchorPoint)
@@ -1164,12 +1174,17 @@
return FloatPoint();
}
-void GraphicsLayerCA::flushCompositingState(const FloatRect& clipRect)
+void GraphicsLayerCA::flushCompositingState(const FloatRect& visibleRect, FlushScope flushScope)
{
- TransformState state(TransformState::UnapplyInverseTransformDirection, FloatQuad(clipRect));
- FloatQuad coverageQuad(clipRect);
+ TransformState state(TransformState::UnapplyInverseTransformDirection, FloatQuad(visibleRect));
+ FloatQuad coverageQuad(visibleRect);
state.setSecondaryQuad(&coverageQuad);
- recursiveCommitChanges(CommitState(), state);
+
+ CommitState commitState;
+ commitState.ancestorHadChanges = visibleRect != m_previousCommittedVisibleRect || flushScope == FlushScope::All;
+ m_previousCommittedVisibleRect = visibleRect;
+
+ recursiveCommitChanges(commitState, state);
}
void GraphicsLayerCA::flushCompositingStateForThisLayerOnly()
@@ -1354,17 +1369,17 @@
// FIXME: we need to take reflections into account when determining whether this layer intersects the coverage rect.
bool intersectsCoverageRect = isViewportConstrained || rects.coverageRect.intersects(FloatRect(m_boundsOrigin, size()));
if (intersectsCoverageRect != m_intersectsCoverageRect) {
- m_uncommittedChanges |= CoverageRectChanged;
+ addUncommittedChanges(CoverageRectChanged);
m_intersectsCoverageRect = intersectsCoverageRect;
}
if (visibleRectChanged) {
- m_uncommittedChanges |= CoverageRectChanged;
+ addUncommittedChanges(CoverageRectChanged);
m_visibleRect = rects.visibleRect;
}
if (coverageRectChanged) {
- m_uncommittedChanges |= CoverageRectChanged;
+ addUncommittedChanges(CoverageRectChanged);
m_coverageRect = rects.coverageRect;
}
}
@@ -1373,8 +1388,12 @@
// animation that contributes maximally to the scale (on every layer with animations down the hierarchy).
void GraphicsLayerCA::recursiveCommitChanges(const CommitState& commitState, const TransformState& state, float pageScaleFactor, const FloatPoint& positionRelativeToBase, bool affectedByPageScale)
{
+ if (!commitState.ancestorHadChanges && !m_uncommittedChanges && !hasDescendantsWithUncommittedChanges())
+ return;
+
TransformState localState = state;
CommitState childCommitState = commitState;
+
bool affectedByTransformAnimation = commitState.ancestorHasTransformAnimation;
bool accumulateTransform = accumulatesTransform(*this);
@@ -1411,7 +1430,11 @@
#endif
bool hadChanges = m_uncommittedChanges;
-
+
+ // FIXME: This could be more fine-grained. Only some types of changes have impact on sublayers.
+ if (!childCommitState.ancestorHadChanges)
+ childCommitState.ancestorHadChanges = hadChanges;
+
if (appliesPageScale()) {
pageScaleFactor = this->pageScaleFactor();
affectedByPageScale = true;
@@ -1450,6 +1473,8 @@
if (GraphicsLayerCA* maskLayer = downcast<GraphicsLayerCA>(m_maskLayer))
maskLayer->commitLayerChangesAfterSublayers(childCommitState);
+ setHasDescendantsWithUncommittedChanges(false);
+
bool hadDirtyRects = m_uncommittedChanges & DirtyRectsChanged;
commitLayerChangesAfterSublayers(childCommitState);
@@ -1564,7 +1589,7 @@
if (!m_uncommittedChanges) {
// Ensure that we cap layer depth in commitLayerChangesAfterSublayers().
if (commitState.treeDepth > cMaxLayerTreeDepth)
- m_uncommittedChanges |= ChildrenChanged;
+ addUncommittedChanges(ChildrenChanged);
}
bool needTiledLayer = requiresTiledLayer(pageScaleFactor);
@@ -1706,7 +1731,7 @@
// Ensure that we cap layer depth in commitLayerChangesAfterSublayers().
if (commitState.treeDepth > cMaxLayerTreeDepth)
- m_uncommittedChanges |= ChildrenChanged;
+ addUncommittedChanges(ChildrenChanged);
}
void GraphicsLayerCA::commitLayerChangesAfterSublayers(CommitState& commitState)
@@ -2116,7 +2141,7 @@
// Release the structural layer.
m_structuralLayer = nullptr;
- m_uncommittedChanges |= structuralLayerChangeFlags;
+ addUncommittedChanges(structuralLayerChangeFlags);
}
return;
}
@@ -2144,7 +2169,7 @@
if (!structuralLayerChanged)
return;
- m_uncommittedChanges |= structuralLayerChangeFlags;
+ addUncommittedChanges(structuralLayerChangeFlags);
// We've changed the layer that our parent added to its sublayer list, so tell it to update
// sublayers again in its commitLayerChangesAfterSublayers().
@@ -3615,7 +3640,7 @@
oldLayer->superlayer()->replaceSublayer(*oldLayer, *m_layer);
}
- m_uncommittedChanges |= ChildrenChanged
+ addUncommittedChanges(ChildrenChanged
| GeometryChanged
| TransformChanged
| ChildrenTransformChanged
@@ -3631,10 +3656,10 @@
| MaskLayerChanged
| OpacityChanged
| NameChanged
- | DebugIndicatorsChanged;
+ | DebugIndicatorsChanged);
if (isTiledLayer)
- m_uncommittedChanges |= CoverageRectChanged;
+ addUncommittedChanges(CoverageRectChanged);
moveAnimations(oldLayer.get(), m_layer.get());
@@ -4008,12 +4033,33 @@
return !(m_uncommittedChanges & TilesAdded);
}
+void GraphicsLayerCA::addUncommittedChanges(LayerChangeFlags flags)
+{
+ m_uncommittedChanges |= flags;
+
+ if (m_isCommittingChanges)
+ return;
+
+ for (auto* ancestor = parent(); ancestor; ancestor = ancestor->parent()) {
+ auto& ancestorCA = static_cast<GraphicsLayerCA&>(*ancestor);
+ ASSERT(!ancestorCA.m_isCommittingChanges);
+ if (ancestorCA.hasDescendantsWithUncommittedChanges())
+ return;
+ ancestorCA.setHasDescendantsWithUncommittedChanges(true);
+ }
+}
+
+void GraphicsLayerCA::setHasDescendantsWithUncommittedChanges(bool value)
+{
+ m_hasDescendantsWithUncommittedChanges = value;
+}
+
void GraphicsLayerCA::noteLayerPropertyChanged(LayerChangeFlags flags, ScheduleFlushOrNot scheduleFlush)
{
bool hadUncommittedChanges = !!m_uncommittedChanges;
bool oldCanThrottleLayerFlush = canThrottleLayerFlush();
- m_uncommittedChanges |= flags;
+ addUncommittedChanges(flags);
if (scheduleFlush == ScheduleFlush) {
bool needsFlush = !hadUncommittedChanges || oldCanThrottleLayerFlush != canThrottleLayerFlush();
Modified: trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.h (215409 => 215410)
--- trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.h 2017-04-17 14:47:04 UTC (rev 215409)
+++ trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.h 2017-04-17 15:00:33 UTC (rev 215410)
@@ -75,6 +75,7 @@
WEBCORE_EXPORT void setReplicatedLayer(GraphicsLayer*) override;
WEBCORE_EXPORT void setPosition(const FloatPoint&) override;
+ WEBCORE_EXPORT void syncPosition(const FloatPoint&) override;
WEBCORE_EXPORT void setAnchorPoint(const FloatPoint3D&) override;
WEBCORE_EXPORT void setSize(const FloatSize&) override;
WEBCORE_EXPORT void setBoundsOrigin(const FloatPoint&) override;
@@ -152,12 +153,13 @@
struct CommitState {
int treeDepth { 0 };
+ bool ancestorHadChanges { false };
bool ancestorHasTransformAnimation { false };
bool ancestorIsViewportConstrained { false };
};
void recursiveCommitChanges(const CommitState&, const TransformState&, float pageScaleFactor = 1, const FloatPoint& positionRelativeToBase = FloatPoint(), bool affectedByPageScale = false);
- WEBCORE_EXPORT void flushCompositingState(const FloatRect&) override;
+ WEBCORE_EXPORT void flushCompositingState(const FloatRect&, FlushScope) override;
WEBCORE_EXPORT void flushCompositingStateForThisLayerOnly() override;
WEBCORE_EXPORT bool visibleRectChangeRequiresFlush(const FloatRect& visibleRect) const override;
@@ -494,8 +496,12 @@
ShapeChanged = 1LLU << 36,
WindRuleChanged = 1LLU << 37,
UserInteractionEnabledChanged = 1LLU << 38,
+ PositionChanged = 1LLU << 39,
};
typedef uint64_t LayerChangeFlags;
+ void addUncommittedChanges(LayerChangeFlags);
+ bool hasDescendantsWithUncommittedChanges() const { return m_hasDescendantsWithUncommittedChanges; }
+ void setHasDescendantsWithUncommittedChanges(bool);
enum ScheduleFlushOrNot { ScheduleFlush, DontScheduleFlush };
void noteLayerPropertyChanged(LayerChangeFlags, ScheduleFlushOrNot = ScheduleFlush);
void noteSublayersChanged(ScheduleFlushOrNot = ScheduleFlush);
@@ -585,7 +591,7 @@
AnimationsMap m_runningAnimations;
Vector<FloatRect> m_dirtyRects;
-
+
std::unique_ptr<DisplayList::DisplayList> m_displayList;
FloatSize m_pixelAlignmentOffset;
@@ -596,8 +602,10 @@
#else
LayerChangeFlags m_uncommittedChanges { CoverageRectChanged };
#endif
+ bool m_hasDescendantsWithUncommittedChanges { false };
bool m_isCommittingChanges { false };
+ FloatRect m_previousCommittedVisibleRect;
};
} // namespace WebCore
Modified: trunk/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.cpp (215409 => 215410)
--- trunk/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.cpp 2017-04-17 14:47:04 UTC (rev 215409)
+++ trunk/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.cpp 2017-04-17 15:00:33 UTC (rev 215410)
@@ -572,7 +572,7 @@
didChangeLayerState();
}
-void CoordinatedGraphicsLayer::flushCompositingState(const FloatRect& rect)
+void CoordinatedGraphicsLayer::flushCompositingState(const FloatRect& rect, FlushScope)
{
if (CoordinatedGraphicsLayer* mask = downcast<CoordinatedGraphicsLayer>(maskLayer()))
mask->flushCompositingStateForThisLayerOnly();
Modified: trunk/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.h (215409 => 215410)
--- trunk/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.h 2017-04-17 14:47:04 UTC (rev 215409)
+++ trunk/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.h 2017-04-17 15:00:33 UTC (rev 215410)
@@ -100,7 +100,7 @@
void setNeedsDisplayInRect(const FloatRect&, ShouldClipToLayer = ClipToLayer) override;
void setContentsNeedsDisplay() override;
void deviceOrPageScaleFactorChanged() override;
- void flushCompositingState(const FloatRect&) override;
+ void flushCompositingState(const FloatRect&, FlushScope) override;
void flushCompositingStateForThisLayerOnly() override;
bool setFilters(const FilterOperations&) override;
bool addAnimation(const KeyframeValueList&, const FloatSize&, const Animation*, const String&, double) override;
Modified: trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp (215409 => 215410)
--- trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp 2017-04-17 14:47:04 UTC (rev 215409)
+++ trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp 2017-04-17 15:00:33 UTC (rev 215410)
@@ -441,6 +441,8 @@
#if PLATFORM(IOS)
FloatRect exposedRect = frameView.exposedContentRect();
LOG_WITH_STREAM(Compositing, stream << "\nRenderLayerCompositor " << this << " flushPendingLayerChanges (root " << isFlushRoot << ") exposedRect " << exposedRect);
+
+ // FIXME: Use optimized flushes.
rootLayer->flushCompositingState(exposedRect);
#else
// Having a m_clipLayer indicates that we're doing scrolling via GraphicsLayers.
@@ -450,7 +452,7 @@
visibleRect.intersect(frameView.viewExposedRect().value());
LOG_WITH_STREAM(Compositing, stream << "\nRenderLayerCompositor " << this << " flushPendingLayerChanges(" << isFlushRoot << ") " << visibleRect);
- rootLayer->flushCompositingState(visibleRect);
+ rootLayer->flushCompositingState(visibleRect, GraphicsLayer::FlushScope::Uncommitted);
LOG_WITH_STREAM(Compositing, stream << "RenderLayerCompositor " << this << " flush complete\n");
#endif
}