Title: [167407] trunk
Revision
167407
Author
ach...@adobe.com
Date
2014-04-16 18:00:26 -0700 (Wed, 16 Apr 2014)

Log Message

Improve performance of the RenderLayerCompositor::OverlapMap
https://bugs.webkit.org/show_bug.cgi?id=115063

Reviewed by Simon Fraser.

PerformanceTests:
Testing the performance of computing the overlap of 5000 layers.

* Layout/layers_overlap_2d.html: Added. Using non-composited layers, to check
that the performance on the non-composited path is not changing with this patch.
* Layout/layers_overlap_3d.html: Added. Records the time to do the layout of 5000
non-overlapping 3D layers.

Source/WebCore:
No new tests, no new functionality or behavior.

Do not use the OverlapMap in RenderLayerCompositor::computeCompositingRequirements if the layer already
has a 3D transform. This way we can avoid a potential expensive lookups when we know for sure the layer
is already supposed to be composited.

Also, added a bounding box of the overlap map, so that it can catch cases when the new layer is not overlapping
any of the previous layers. This is pretty common when having composited layers laid out in a vertical/horizontal list.

* rendering/RenderLayerCompositor.cpp:
(OverlapMapContainer):
(WebCore::OverlapMapContainer::add):
(WebCore::OverlapMapContainer::overlapsLayers):
(WebCore::OverlapMapContainer::unite):
(WebCore):
(WebCore::RenderLayerCompositor::OverlapMap::add):
(WebCore::RenderLayerCompositor::OverlapMap::overlapsLayers):
(WebCore::RenderLayerCompositor::OverlapMap::pushCompositingContainer):
(WebCore::RenderLayerCompositor::OverlapMap::popCompositingContainer):
(RenderLayerCompositor::OverlapMap):
(WebCore::RenderLayerCompositor::computeCompositingRequirements):

Modified Paths

Added Paths

Diff

Modified: trunk/PerformanceTests/ChangeLog (167406 => 167407)


--- trunk/PerformanceTests/ChangeLog	2014-04-17 00:56:35 UTC (rev 167406)
+++ trunk/PerformanceTests/ChangeLog	2014-04-17 01:00:26 UTC (rev 167407)
@@ -1,3 +1,17 @@
+2014-04-16  Alexandru Chiculita  <ach...@adobe.com>
+
+        Improve performance of the RenderLayerCompositor::OverlapMap
+        https://bugs.webkit.org/show_bug.cgi?id=115063
+
+        Reviewed by Simon Fraser.
+
+        Testing the performance of computing the overlap of 5000 layers.
+
+        * Layout/layers_overlap_2d.html: Added. Using non-composited layers, to check
+        that the performance on the non-composited path is not changing with this patch.
+        * Layout/layers_overlap_3d.html: Added. Records the time to do the layout of 5000
+        non-overlapping 3D layers.
+
 2014-04-15  Zoltan Horvath  <zol...@webkit.org>
 
         [CSS Shapes] Linking stylesheet instead of inline style definition has ruined ShapesRegions test

Added: trunk/PerformanceTests/Layout/layers_overlap_2d.html (0 => 167407)


--- trunk/PerformanceTests/Layout/layers_overlap_2d.html	                        (rev 0)
+++ trunk/PerformanceTests/Layout/layers_overlap_2d.html	2014-04-17 01:00:26 UTC (rev 167407)
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>Performance tester for non-overlaping 2D layers</title>
+        <style>
+            .container {
+                position: relative;
+                width: 20px;
+                height: 20px;
+                border: 1px solid #AAA;
+                margin: 0 auto 5px;
+            }
+
+            .box {
+                width: 100%;
+                height: 100%;
+                position: absolute;
+                background: red;
+            }
+
+            .composited {
+                -webkit-transform: translateZ(1px);
+            }
+        </style>
+        <script src=""
+    </head>
+    <body>
+        <pre id="log"></pre>
+        <script>
+            function createTestFunction(count) {
+                return function() {
+                    var container = document.createElement("div");
+                    for(i = 0; i < count; ++i) {
+                        var outer = document.createElement('div');
+                        outer.className = 'container';
+                        var inner = document.createElement('div');
+                        inner.className = 'box';
+                        if (i == 0) {
+                            // Use at least one 3D layer to trigger the overlap map checking.
+                            inner.className += " composited";
+                        }
+                        outer.appendChild(inner);
+                        container.appendChild(outer);
+                    }
+                    document.body.appendChild(container);
+                    // Force a layout update.
+                    document.body.clientHeight;
+                    container.remove();
+                }
+            }
+            PerfTestRunner.measureTime({run: createTestFunction(5000)});
+        </script>
+    </body>
+</html>

Added: trunk/PerformanceTests/Layout/layers_overlap_3d.html (0 => 167407)


--- trunk/PerformanceTests/Layout/layers_overlap_3d.html	                        (rev 0)
+++ trunk/PerformanceTests/Layout/layers_overlap_3d.html	2014-04-17 01:00:26 UTC (rev 167407)
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>Performance tester for non-overlaping 3D layers</title>
+        <style>
+            .container {
+                width: 20px;
+                height: 20px;
+                border: 1px solid #AAA;
+                margin: 0 auto 5px;
+                -webkit-perspective: 400px;
+            }
+
+            .box {
+                width: 100%;
+                height: 100%;
+                position: absolute;
+                background: red;
+                -webkit-transform: translateZ( -200px );
+            }
+        </style>
+        <script src=""
+    </head>
+    <body>
+        <pre id="log"></pre>
+        <script>
+            function createTestFunction(count) {
+                return function() {
+                    var container = document.createElement("div");
+                    for(i = 0; i < count; ++i) {
+                        var outer = document.createElement('div');
+                        outer.className = 'container';
+                        var inner = document.createElement('div');
+                        inner.className = 'box';
+                        outer.appendChild(inner);
+                        container.appendChild(outer);
+                    }
+                    document.body.appendChild(container);
+                    // Force a layout update.
+                    document.body.clientHeight;
+                    container.remove();
+                }
+            }
+            PerfTestRunner.measureTime({run: createTestFunction(5000)});
+        </script>
+    </body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (167406 => 167407)


--- trunk/Source/WebCore/ChangeLog	2014-04-17 00:56:35 UTC (rev 167406)
+++ trunk/Source/WebCore/ChangeLog	2014-04-17 01:00:26 UTC (rev 167407)
@@ -1,3 +1,33 @@
+2014-04-16  Alexandru Chiculita  <ach...@adobe.com>
+
+        Improve performance of the RenderLayerCompositor::OverlapMap
+        https://bugs.webkit.org/show_bug.cgi?id=115063
+
+        Reviewed by Simon Fraser.
+
+        No new tests, no new functionality or behavior.
+
+        Do not use the OverlapMap in RenderLayerCompositor::computeCompositingRequirements if the layer already
+        has a 3D transform. This way we can avoid a potential expensive lookups when we know for sure the layer
+        is already supposed to be composited. 
+
+        Also, added a bounding box of the overlap map, so that it can catch cases when the new layer is not overlapping
+        any of the previous layers. This is pretty common when having composited layers laid out in a vertical/horizontal list.
+
+
+        * rendering/RenderLayerCompositor.cpp:
+        (OverlapMapContainer):
+        (WebCore::OverlapMapContainer::add):
+        (WebCore::OverlapMapContainer::overlapsLayers):
+        (WebCore::OverlapMapContainer::unite):
+        (WebCore):
+        (WebCore::RenderLayerCompositor::OverlapMap::add):
+        (WebCore::RenderLayerCompositor::OverlapMap::overlapsLayers):
+        (WebCore::RenderLayerCompositor::OverlapMap::pushCompositingContainer):
+        (WebCore::RenderLayerCompositor::OverlapMap::popCompositingContainer):
+        (RenderLayerCompositor::OverlapMap):
+        (WebCore::RenderLayerCompositor::computeCompositingRequirements):
+
 2014-04-16  Brian J. Burg  <b...@cs.washington.edu>
 
         Web Replay: memoize fallback time values for document.lastModified

Modified: trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp (167406 => 167407)


--- trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp	2014-04-17 00:56:35 UTC (rev 167406)
+++ trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp	2014-04-17 01:00:26 UTC (rev 167407)
@@ -105,6 +105,38 @@
 
 using namespace HTMLNames;
 
+class OverlapMapContainer {
+public:
+    void add(const IntRect& bounds)
+    {
+        m_layerRects.append(bounds);
+        m_boundingBox.unite(bounds);
+    }
+
+    bool overlapsLayers(const IntRect& bounds) const
+    {
+        // Checking with the bounding box will quickly reject cases when
+        // layers are created for lists of items going in one direction and
+        // never overlap with each other.
+        if (!bounds.intersects(m_boundingBox))
+            return false;
+        for (unsigned i = 0; i < m_layerRects.size(); i++) {
+            if (m_layerRects[i].intersects(bounds))
+                return true;
+        }
+        return false;
+    }
+
+    void unite(const OverlapMapContainer& otherContainer)
+    {
+        m_layerRects.appendVector(otherContainer.m_layerRects);
+        m_boundingBox.unite(otherContainer.m_boundingBox);
+    }
+private:
+    Vector<IntRect> m_layerRects;
+    IntRect m_boundingBox;
+};
+
 class RenderLayerCompositor::OverlapMap {
     WTF_MAKE_NONCOPYABLE(OverlapMap);
 public:
@@ -123,7 +155,7 @@
         // contribute to overlap as soon as their composited ancestor has been
         // recursively processed and popped off the stack.
         ASSERT(m_overlapStack.size() >= 2);
-        m_overlapStack[m_overlapStack.size() - 2].append(bounds);
+        m_overlapStack[m_overlapStack.size() - 2].add(bounds);
         m_layers.add(layer);
     }
 
@@ -134,7 +166,7 @@
 
     bool overlapsLayers(const IntRect& bounds) const
     {
-        return m_overlapStack.last().intersects(bounds);
+        return m_overlapStack.last().overlapsLayers(bounds);
     }
 
     bool isEmpty()
@@ -144,12 +176,12 @@
 
     void pushCompositingContainer()
     {
-        m_overlapStack.append(RectList());
+        m_overlapStack.append(OverlapMapContainer());
     }
 
     void popCompositingContainer()
     {
-        m_overlapStack[m_overlapStack.size() - 2].append(m_overlapStack.last());
+        m_overlapStack[m_overlapStack.size() - 2].unite(m_overlapStack.last());
         m_overlapStack.removeLast();
     }
 
@@ -185,7 +217,7 @@
         }
     };
 
-    Vector<RectList> m_overlapStack;
+    Vector<OverlapMapContainer> m_overlapStack;
     HashSet<const RenderLayer*> m_layers;
     RenderGeometryMap m_geometryMap;
 };
@@ -1090,12 +1122,19 @@
     
     // Clear the flag
     layer.setHasCompositingDescendant(false);
+    layer.setIndirectCompositingReason(RenderLayer::NoIndirectCompositingReason);
 
+    // Check if the layer needs to be composited for non-indirect reasons (ex. 3D transform).
+    // We use this value to avoid checking the overlap-map, if we know for sure the layer
+    // is already going to be composited for other reasons.
+    bool willBeComposited = needsToBeComposited(layer);
+
     RenderLayer::IndirectCompositingReason compositingReason = compositingState.m_subtreeIsCompositing ? RenderLayer::IndirectCompositingForStacking : RenderLayer::NoIndirectCompositingReason;
-
     bool haveComputedBounds = false;
     IntRect absBounds;
-    if (overlapMap && !overlapMap->isEmpty() && compositingState.m_testingOverlap) {
+
+    // If we know for sure the layer is going to be composited, don't bother looking it up in the overlap map
+    if (!willBeComposited && overlapMap && !overlapMap->isEmpty() && compositingState.m_testingOverlap) {
         // If we're testing for overlap, we only need to composite if we overlap something that is already composited.
         absBounds = enclosingIntRect(overlapMap->geometryMap().absoluteRect(layer.overlapBounds()));
 
@@ -1117,6 +1156,11 @@
 
     layer.setIndirectCompositingReason(compositingReason);
 
+    // Check if the computed indirect reason will force the layer to become composited.
+    if (!willBeComposited && layer.mustCompositeForIndirectReasons() && canBeComposited(layer))
+        willBeComposited = true;
+    ASSERT(willBeComposited == needsToBeComposited(layer));
+
     // The children of this layer don't need to composite, unless there is
     // a compositing layer among them, so start by inheriting the compositing
     // ancestor with m_subtreeIsCompositing set to false.
@@ -1126,7 +1170,6 @@
     childState.m_hasUnisolatedCompositedBlendingDescendants = false;
 #endif
 
-    bool willBeComposited = needsToBeComposited(layer);
     if (willBeComposited) {
         // Tell the parent it has compositing descendants.
         compositingState.m_subtreeIsCompositing = true;
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to