Changeset 120395 in webkit
- Timestamp:
- Jun 14, 2012 9:17:39 PM (12 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r120393 r120395 1 2012-06-14 Julien Chaffraix <jchaffraix@webkit.org> 2 3 RenderLayer subtrees without any self-painting layer shouldn't be walked during painting 4 https://bugs.webkit.org/show_bug.cgi?id=88888 5 6 Reviewed by Simon Fraser. 7 8 Performance optimization, covered by existing tests. 9 10 The gist of this change is to add a has-self-painting-layer-descendant flag (including an 11 invalidation logic) that is used to avoid walking subtrees without any self-painting layer. 12 13 On http://dglazkov.github.com/performance-tests/biggrid.html with a 100,000 rows 14 by 100 columns table, it brings the paint time during scrolling from ~45ms to ~6ms 15 on my machine. The test case is a pathologic example here but the optimization should 16 apply in other cases. 17 18 The new update logic piggy-backs on top of the existing updateVisibilityStatus() one that 19 got repurposed and renamed as part of this change. 20 21 * rendering/RenderLayer.cpp: 22 (WebCore::RenderLayer::RenderLayer): 23 (WebCore::RenderLayer::addChild): 24 (WebCore::RenderLayer::removeChild): 25 (WebCore::RenderLayer::styleChanged): 26 These functions were updated to dirty / set the new flag. 27 28 (WebCore::RenderLayer::dirtyAncestorChainHasSelfPaintingLayerDescendantStatus): 29 (WebCore::RenderLayer::setAncestorChainHasSelfPaintingLayerDescendant): 30 Added those functions to handle setting / invalidating the new flag. 31 32 (WebCore::RenderLayer::updateSelfPaintingLayerAfterStyleChange): 33 Added this function to handle style update. 34 35 (WebCore::RenderLayer::paintLayer): 36 (WebCore::RenderLayer::paintLayerContentsAndReflection): 37 (WebCore::RenderLayer::paintLayerContents): 38 (WebCore::RenderLayer::paintList): 39 Changed this logic to bail out if we have no self-painting descendants. This is what 40 is giving the performance improvement. Also added some performance ASSERTs to ensure 41 the methods are not called when they shouldn't. 42 43 (WebCore::RenderLayer::updateDescendantDependentFlags): 44 Renamed from updateVisibilityStatus to account for the new usage. 45 46 (WebCore::RenderLayer::updateLayerPositions): 47 (WebCore::RenderLayer::updateLayerPositionsAfterScroll): 48 (WebCore::RenderLayer::collectLayers): 49 * rendering/RenderLayerBacking.cpp: 50 (WebCore::RenderLayerBacking::updateGraphicsLayerGeometry): 51 Updated after updateVisibilityStatus rename. 52 53 * rendering/RenderLayer.h: 54 (WebCore::RenderLayer::hasSelfPaintingLayerDescendant): 55 Added the declaration of the new functions as well as the new flag and dirty bit. 56 1 57 2012-06-14 Tony Payne <tpayne@chromium.org> 2 58 -
trunk/Source/WebCore/rendering/RenderLayer.cpp
r119893 r120395 130 130 , m_scrollDimensionsDirty(true) 131 131 , m_normalFlowListDirty(true) 132 , m_hasSelfPaintingLayerDescendant(false) 133 , m_hasSelfPaintingLayerDescendantDirty(false) 132 134 , m_isRootLayer(renderer->isRenderView()) 133 135 , m_usedTransparency(false) … … 364 366 positionOverflowControls(toSize(roundedIntPoint(offset))); 365 367 366 update VisibilityStatus();368 updateDescendantDependentFlags(); 367 369 368 370 if (flags & UpdatePagination) … … 443 445 } 444 446 447 void RenderLayer::setAncestorChainHasSelfPaintingLayerDescendant() 448 { 449 for (RenderLayer* layer = this; layer; layer = layer->parent()) { 450 if (!layer->m_hasSelfPaintingLayerDescendantDirty && layer->hasSelfPaintingLayerDescendant()) 451 break; 452 453 layer->m_hasSelfPaintingLayerDescendantDirty = false; 454 layer->m_hasSelfPaintingLayerDescendant = true; 455 } 456 } 457 458 void RenderLayer::dirtyAncestorChainHasSelfPaintingLayerDescendantStatus() 459 { 460 for (RenderLayer* layer = this; layer; layer = layer->parent()) { 461 layer->m_hasSelfPaintingLayerDescendantDirty = true; 462 // If we have reached a self-painting layer, we know our parent should have a self-painting descendant 463 // in this case, there is no need to dirty our ancestors further. 464 if (layer->isSelfPaintingLayer()) { 465 ASSERT(!parent() || parent()->m_hasSelfPaintingLayerDescendantDirty || parent()->hasSelfPaintingLayerDescendant()); 466 break; 467 } 468 } 469 } 470 445 471 void RenderLayer::computeRepaintRects(LayoutPoint* offsetFromRoot) 446 472 { … … 465 491 // FIXME: This shouldn't be needed, but there are some corner cases where 466 492 // these flags are still dirty. Update so that the check below is valid. 467 update VisibilityStatus();493 updateDescendantDependentFlags(); 468 494 469 495 // If we have no visible content and no visible descendants, there is no point recomputing … … 657 683 } 658 684 659 void RenderLayer::update VisibilityStatus()660 { 661 if (m_visibleDescendantStatusDirty ) {685 void RenderLayer::updateDescendantDependentFlags() 686 { 687 if (m_visibleDescendantStatusDirty || m_hasSelfPaintingLayerDescendantDirty) { 662 688 m_hasVisibleDescendant = false; 689 m_hasSelfPaintingLayerDescendant = false; 663 690 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) { 664 child->updateVisibilityStatus(); 665 if (child->m_hasVisibleContent || child->m_hasVisibleDescendant) { 666 m_hasVisibleDescendant = true; 691 child->updateDescendantDependentFlags(); 692 693 bool hasVisibleDescendant = child->m_hasVisibleContent || child->m_hasVisibleDescendant; 694 bool hasSelfPaintingLayerDescendant = child->isSelfPaintingLayer() || child->hasSelfPaintingLayerDescendant(); 695 696 m_hasVisibleDescendant |= hasVisibleDescendant; 697 m_hasSelfPaintingLayerDescendant |= hasSelfPaintingLayerDescendant; 698 699 if (m_hasVisibleDescendant && m_hasSelfPaintingLayerDescendant) 667 700 break; 668 }669 701 } 670 702 m_visibleDescendantStatusDirty = false; 703 m_hasSelfPaintingLayerDescendantDirty = false; 671 704 } 672 705 … … 1243 1276 } 1244 1277 1245 child->update VisibilityStatus();1278 child->updateDescendantDependentFlags(); 1246 1279 if (child->m_hasVisibleContent || child->m_hasVisibleDescendant) 1247 1280 childVisibilityChanged(true); 1248 1281 1282 if (child->isSelfPaintingLayer() || child->hasSelfPaintingLayerDescendant()) 1283 setAncestorChainHasSelfPaintingLayerDescendant(); 1284 1249 1285 #if USE(ACCELERATED_COMPOSITING) 1250 1286 compositor()->layerWasAdded(this, child); … … 1283 1319 oldChild->setParent(0); 1284 1320 1285 oldChild->update VisibilityStatus();1321 oldChild->updateDescendantDependentFlags(); 1286 1322 if (oldChild->m_hasVisibleContent || oldChild->m_hasVisibleDescendant) 1287 1323 childVisibilityChanged(false); 1288 1324 1325 if (oldChild->isSelfPaintingLayer() || oldChild->hasSelfPaintingLayerDescendant()) 1326 dirtyAncestorChainHasSelfPaintingLayerDescendantStatus(); 1327 1289 1328 return oldChild; 1290 1329 } … … 2883 2922 2884 2923 // Non self-painting leaf layers don't need to be painted as their renderer() should properly paint itself. 2885 if (!isSelfPaintingLayer() && ! firstChild())2924 if (!isSelfPaintingLayer() && !hasSelfPaintingLayerDescendant()) 2886 2925 return; 2887 2926 … … 2953 2992 PaintLayerFlags paintFlags) 2954 2993 { 2994 ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant()); 2995 2955 2996 PaintLayerFlags localPaintFlags = paintFlags & ~(PaintLayerAppliedTransform); 2956 2997 … … 2972 3013 PaintLayerFlags paintFlags) 2973 3014 { 3015 ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant()); 3016 2974 3017 PaintLayerFlags localPaintFlags = paintFlags & ~(PaintLayerAppliedTransform); 2975 3018 bool haveTransparency = localPaintFlags & PaintLayerHaveTransparency; … … 3164 3207 { 3165 3208 if (!list) 3209 return; 3210 3211 if (!hasSelfPaintingLayerDescendant()) 3166 3212 return; 3167 3213 … … 4539 4585 void RenderLayer::collectLayers(bool includeHiddenLayers, Vector<RenderLayer*>*& posBuffer, Vector<RenderLayer*>*& negBuffer) 4540 4586 { 4541 update VisibilityStatus();4587 updateDescendantDependentFlags(); 4542 4588 4543 4589 // Overflow layers are just painted by their enclosing layers, so they don't get put in zorder lists. … … 4675 4721 } 4676 4722 4723 void RenderLayer::updateSelfPaintingLayerAfterStyleChange(const RenderStyle*) 4724 { 4725 bool isSelfPaintingLayer = shouldBeSelfPaintingLayer(); 4726 if (m_isSelfPaintingLayer == isSelfPaintingLayer) 4727 return; 4728 4729 m_isSelfPaintingLayer = isSelfPaintingLayer; 4730 if (!parent()) 4731 return; 4732 if (isSelfPaintingLayer) 4733 parent()->setAncestorChainHasSelfPaintingLayerDescendant(); 4734 else 4735 parent()->dirtyAncestorChainHasSelfPaintingLayerDescendantStatus(); 4736 } 4737 4677 4738 void RenderLayer::updateStackingContextsAfterStyleChange(const RenderStyle* oldStyle) 4678 4739 { … … 4745 4806 } 4746 4807 4747 m_isSelfPaintingLayer = shouldBeSelfPaintingLayer();4748 4749 4808 if (renderer()->style()->overflowX() == OMARQUEE && renderer()->style()->marqueeBehavior() != MNONE && renderer()->isBox()) { 4750 4809 if (!m_marquee) … … 4757 4816 } 4758 4817 4818 updateSelfPaintingLayerAfterStyleChange(oldStyle); 4759 4819 updateStackingContextsAfterStyleChange(oldStyle); 4760 4820 updateScrollbarsAfterStyleChange(oldStyle); … … 4782 4842 4783 4843 #if USE(ACCELERATED_COMPOSITING) 4784 update VisibilityStatus();4844 updateDescendantDependentFlags(); 4785 4845 updateTransform(); 4786 4846 -
trunk/Source/WebCore/rendering/RenderLayer.h
r119996 r120395 445 445 void dirtyVisibleContentStatus(); 446 446 447 // FIXME: We should ASSERT(!m_hasSelfPaintingLayerDescendantDirty); here but we hit the same bugs as visible content above. 448 // Part of the issue is with subtree relayout: we don't check if our ancestors have some descendant flags dirty, missing some updates. 449 bool hasSelfPaintingLayerDescendant() const { return m_hasSelfPaintingLayerDescendant; } 450 447 451 // Gets the nearest enclosing positioned ancestor layer (also includes 448 452 // the <html> layer and the root layer). … … 652 656 bool isDirtyStackingContext() const { return m_zOrderListsDirty && isStackingContext(); } 653 657 658 void setAncestorChainHasSelfPaintingLayerDescendant(); 659 void dirtyAncestorChainHasSelfPaintingLayerDescendantStatus(); 660 654 661 void computeRepaintRects(LayoutPoint* offsetFromRoot = 0); 655 662 void clearRepaintRects(); … … 661 668 bool shouldRepaintAfterLayout() const; 662 669 670 void updateSelfPaintingLayerAfterStyleChange(const RenderStyle* oldStyle); 663 671 void updateStackingContextsAfterStyleChange(const RenderStyle* oldStyle); 664 672 … … 777 785 void childVisibilityChanged(bool newVisibility); 778 786 void dirtyVisibleDescendantStatus(); 779 void updateVisibilityStatus(); 787 788 void updateDescendantDependentFlags(); 780 789 781 790 // This flag is computed by RenderLayerCompositor, which knows more about 3d hierarchies than we do. … … 873 882 bool m_isSelfPaintingLayer : 1; 874 883 884 // If have no self-painting descendants, we don't have to walk our children during painting. This can lead to 885 // significant savings, especially if the tree has lots of non-self-painting layers grouped together (e.g. table cells). 886 bool m_hasSelfPaintingLayerDescendant : 1; 887 bool m_hasSelfPaintingLayerDescendantDirty : 1; 888 875 889 const bool m_isRootLayer : 1; 876 890 -
trunk/Source/WebCore/rendering/RenderLayerBacking.cpp
r120340 r120395 425 425 #endif 426 426 427 m_owningLayer->update VisibilityStatus();427 m_owningLayer->updateDescendantDependentFlags(); 428 428 429 429 // m_graphicsLayer is the corresponding GraphicsLayer for this RenderLayer and its non-compositing
Note: See TracChangeset
for help on using the changeset viewer.