<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[167407] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/167407">167407</a></dd>
<dt>Author</dt> <dd>achicu@adobe.com</dd>
<dt>Date</dt> <dd>2014-04-16 18:00:26 -0700 (Wed, 16 Apr 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>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):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkPerformanceTestsChangeLog">trunk/PerformanceTests/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderLayerCompositorcpp">trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkPerformanceTestsLayoutlayers_overlap_2dhtml">trunk/PerformanceTests/Layout/layers_overlap_2d.html</a></li>
<li><a href="#trunkPerformanceTestsLayoutlayers_overlap_3dhtml">trunk/PerformanceTests/Layout/layers_overlap_3d.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkPerformanceTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/PerformanceTests/ChangeLog (167406 => 167407)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/ChangeLog        2014-04-17 00:56:35 UTC (rev 167406)
+++ trunk/PerformanceTests/ChangeLog        2014-04-17 01:00:26 UTC (rev 167407)
</span><span class="lines">@@ -1,3 +1,17 @@
</span><ins>+2014-04-16  Alexandru Chiculita  &lt;achicu@adobe.com&gt;
+
+        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.
+
</ins><span class="cx"> 2014-04-15  Zoltan Horvath  &lt;zoltan@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         [CSS Shapes] Linking stylesheet instead of inline style definition has ruined ShapesRegions test
</span></span></pre></div>
<a id="trunkPerformanceTestsLayoutlayers_overlap_2dhtml"></a>
<div class="addfile"><h4>Added: trunk/PerformanceTests/Layout/layers_overlap_2d.html (0 => 167407)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,54 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+    &lt;head&gt;
+        &lt;title&gt;Performance tester for non-overlaping 2D layers&lt;/title&gt;
+        &lt;style&gt;
+            .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);
+            }
+        &lt;/style&gt;
+        &lt;script src=&quot;../resources/runner.js&quot;&gt;&lt;/script&gt;
+    &lt;/head&gt;
+    &lt;body&gt;
+        &lt;pre id=&quot;log&quot;&gt;&lt;/pre&gt;
+        &lt;script&gt;
+            function createTestFunction(count) {
+                return function() {
+                    var container = document.createElement(&quot;div&quot;);
+                    for(i = 0; i &lt; 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 += &quot; composited&quot;;
+                        }
+                        outer.appendChild(inner);
+                        container.appendChild(outer);
+                    }
+                    document.body.appendChild(container);
+                    // Force a layout update.
+                    document.body.clientHeight;
+                    container.remove();
+                }
+            }
+            PerfTestRunner.measureTime({run: createTestFunction(5000)});
+        &lt;/script&gt;
+    &lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkPerformanceTestsLayoutlayers_overlap_3dhtml"></a>
<div class="addfile"><h4>Added: trunk/PerformanceTests/Layout/layers_overlap_3d.html (0 => 167407)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,47 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+    &lt;head&gt;
+        &lt;title&gt;Performance tester for non-overlaping 3D layers&lt;/title&gt;
+        &lt;style&gt;
+            .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 );
+            }
+        &lt;/style&gt;
+        &lt;script src=&quot;../resources/runner.js&quot;&gt;&lt;/script&gt;
+    &lt;/head&gt;
+    &lt;body&gt;
+        &lt;pre id=&quot;log&quot;&gt;&lt;/pre&gt;
+        &lt;script&gt;
+            function createTestFunction(count) {
+                return function() {
+                    var container = document.createElement(&quot;div&quot;);
+                    for(i = 0; i &lt; 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)});
+        &lt;/script&gt;
+    &lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (167406 => 167407)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -1,3 +1,33 @@
</span><ins>+2014-04-16  Alexandru Chiculita  &lt;achicu@adobe.com&gt;
+
+        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):
+
</ins><span class="cx"> 2014-04-16  Brian J. Burg  &lt;burg@cs.washington.edu&gt;
</span><span class="cx"> 
</span><span class="cx">         Web Replay: memoize fallback time values for document.lastModified
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderLayerCompositorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp (167406 => 167407)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -105,6 +105,38 @@
</span><span class="cx"> 
</span><span class="cx"> using namespace HTMLNames;
</span><span class="cx"> 
</span><ins>+class OverlapMapContainer {
+public:
+    void add(const IntRect&amp; bounds)
+    {
+        m_layerRects.append(bounds);
+        m_boundingBox.unite(bounds);
+    }
+
+    bool overlapsLayers(const IntRect&amp; 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 &lt; m_layerRects.size(); i++) {
+            if (m_layerRects[i].intersects(bounds))
+                return true;
+        }
+        return false;
+    }
+
+    void unite(const OverlapMapContainer&amp; otherContainer)
+    {
+        m_layerRects.appendVector(otherContainer.m_layerRects);
+        m_boundingBox.unite(otherContainer.m_boundingBox);
+    }
+private:
+    Vector&lt;IntRect&gt; m_layerRects;
+    IntRect m_boundingBox;
+};
+
</ins><span class="cx"> class RenderLayerCompositor::OverlapMap {
</span><span class="cx">     WTF_MAKE_NONCOPYABLE(OverlapMap);
</span><span class="cx"> public:
</span><span class="lines">@@ -123,7 +155,7 @@
</span><span class="cx">         // contribute to overlap as soon as their composited ancestor has been
</span><span class="cx">         // recursively processed and popped off the stack.
</span><span class="cx">         ASSERT(m_overlapStack.size() &gt;= 2);
</span><del>-        m_overlapStack[m_overlapStack.size() - 2].append(bounds);
</del><ins>+        m_overlapStack[m_overlapStack.size() - 2].add(bounds);
</ins><span class="cx">         m_layers.add(layer);
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -134,7 +166,7 @@
</span><span class="cx"> 
</span><span class="cx">     bool overlapsLayers(const IntRect&amp; bounds) const
</span><span class="cx">     {
</span><del>-        return m_overlapStack.last().intersects(bounds);
</del><ins>+        return m_overlapStack.last().overlapsLayers(bounds);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     bool isEmpty()
</span><span class="lines">@@ -144,12 +176,12 @@
</span><span class="cx"> 
</span><span class="cx">     void pushCompositingContainer()
</span><span class="cx">     {
</span><del>-        m_overlapStack.append(RectList());
</del><ins>+        m_overlapStack.append(OverlapMapContainer());
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void popCompositingContainer()
</span><span class="cx">     {
</span><del>-        m_overlapStack[m_overlapStack.size() - 2].append(m_overlapStack.last());
</del><ins>+        m_overlapStack[m_overlapStack.size() - 2].unite(m_overlapStack.last());
</ins><span class="cx">         m_overlapStack.removeLast();
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -185,7 +217,7 @@
</span><span class="cx">         }
</span><span class="cx">     };
</span><span class="cx"> 
</span><del>-    Vector&lt;RectList&gt; m_overlapStack;
</del><ins>+    Vector&lt;OverlapMapContainer&gt; m_overlapStack;
</ins><span class="cx">     HashSet&lt;const RenderLayer*&gt; m_layers;
</span><span class="cx">     RenderGeometryMap m_geometryMap;
</span><span class="cx"> };
</span><span class="lines">@@ -1090,12 +1122,19 @@
</span><span class="cx">     
</span><span class="cx">     // Clear the flag
</span><span class="cx">     layer.setHasCompositingDescendant(false);
</span><ins>+    layer.setIndirectCompositingReason(RenderLayer::NoIndirectCompositingReason);
</ins><span class="cx"> 
</span><ins>+    // 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);
+
</ins><span class="cx">     RenderLayer::IndirectCompositingReason compositingReason = compositingState.m_subtreeIsCompositing ? RenderLayer::IndirectCompositingForStacking : RenderLayer::NoIndirectCompositingReason;
</span><del>-
</del><span class="cx">     bool haveComputedBounds = false;
</span><span class="cx">     IntRect absBounds;
</span><del>-    if (overlapMap &amp;&amp; !overlapMap-&gt;isEmpty() &amp;&amp; compositingState.m_testingOverlap) {
</del><ins>+
+    // If we know for sure the layer is going to be composited, don't bother looking it up in the overlap map
+    if (!willBeComposited &amp;&amp; overlapMap &amp;&amp; !overlapMap-&gt;isEmpty() &amp;&amp; compositingState.m_testingOverlap) {
</ins><span class="cx">         // If we're testing for overlap, we only need to composite if we overlap something that is already composited.
</span><span class="cx">         absBounds = enclosingIntRect(overlapMap-&gt;geometryMap().absoluteRect(layer.overlapBounds()));
</span><span class="cx"> 
</span><span class="lines">@@ -1117,6 +1156,11 @@
</span><span class="cx"> 
</span><span class="cx">     layer.setIndirectCompositingReason(compositingReason);
</span><span class="cx"> 
</span><ins>+    // Check if the computed indirect reason will force the layer to become composited.
+    if (!willBeComposited &amp;&amp; layer.mustCompositeForIndirectReasons() &amp;&amp; canBeComposited(layer))
+        willBeComposited = true;
+    ASSERT(willBeComposited == needsToBeComposited(layer));
+
</ins><span class="cx">     // The children of this layer don't need to composite, unless there is
</span><span class="cx">     // a compositing layer among them, so start by inheriting the compositing
</span><span class="cx">     // ancestor with m_subtreeIsCompositing set to false.
</span><span class="lines">@@ -1126,7 +1170,6 @@
</span><span class="cx">     childState.m_hasUnisolatedCompositedBlendingDescendants = false;
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-    bool willBeComposited = needsToBeComposited(layer);
</del><span class="cx">     if (willBeComposited) {
</span><span class="cx">         // Tell the parent it has compositing descendants.
</span><span class="cx">         compositingState.m_subtreeIsCompositing = true;
</span></span></pre>
</div>
</div>

</body>
</html>