[chromium] Skip willDraw() and didDraw() on fully occluded layers
authordanakj@chromium.org <danakj@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 8 Jun 2012 21:37:33 +0000 (21:37 +0000)
committerdanakj@chromium.org <danakj@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 8 Jun 2012 21:37:33 +0000 (21:37 +0000)
https://bugs.webkit.org/show_bug.cgi?id=88435

Reviewed by Adrienne Walker.

Source/WebCore:

Current willDraw() is called on all layers with non-empty
visibleLayerRect and non-empty scissorRect. This excludes
layers outside the viewport, but does not exclude occluded
layers. We add a check for occlusion to calculateRenderPasses
in order to avoid willDraw() when it will be culled anyway.

We prevent didDraw() from being called for occluded layers, for
which we did not call didDraw() by holding a vector of layers
for which we did call willDraw(). This lets us avoid storing a
flag on the layers, or computing occlusion again in
didDrawAllLayers.

Unit test: CCLayerTreeHostImplTest.willDrawNotCalledOnOccludedLayer

* platform/graphics/chromium/cc/CCLayerTreeHostImpl.cpp:
(WebCore::CCLayerTreeHostImpl::calculateRenderPasses):
(WebCore::CCLayerTreeHostImpl::prepareToDraw):
(WebCore::CCLayerTreeHostImpl::didDrawAllLayers):
* platform/graphics/chromium/cc/CCLayerTreeHostImpl.h:
(FrameData):
(CCLayerTreeHostImpl):

Source/WebKit/chromium:

* tests/CCLayerTreeHostImplTest.cpp:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@119867 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostImpl.cpp
Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostImpl.h
Source/WebKit/chromium/ChangeLog
Source/WebKit/chromium/tests/CCLayerTreeHostImplTest.cpp

index b03a748..0703901 100644 (file)
@@ -1,3 +1,32 @@
+2012-06-08  Dana Jansens  <danakj@chromium.org>
+
+        [chromium] Skip willDraw() and didDraw() on fully occluded layers
+        https://bugs.webkit.org/show_bug.cgi?id=88435
+
+        Reviewed by Adrienne Walker.
+
+        Current willDraw() is called on all layers with non-empty
+        visibleLayerRect and non-empty scissorRect. This excludes
+        layers outside the viewport, but does not exclude occluded
+        layers. We add a check for occlusion to calculateRenderPasses
+        in order to avoid willDraw() when it will be culled anyway.
+
+        We prevent didDraw() from being called for occluded layers, for
+        which we did not call didDraw() by holding a vector of layers
+        for which we did call willDraw(). This lets us avoid storing a
+        flag on the layers, or computing occlusion again in
+        didDrawAllLayers.
+
+        Unit test: CCLayerTreeHostImplTest.willDrawNotCalledOnOccludedLayer
+
+        * platform/graphics/chromium/cc/CCLayerTreeHostImpl.cpp:
+        (WebCore::CCLayerTreeHostImpl::calculateRenderPasses):
+        (WebCore::CCLayerTreeHostImpl::prepareToDraw):
+        (WebCore::CCLayerTreeHostImpl::didDrawAllLayers):
+        * platform/graphics/chromium/cc/CCLayerTreeHostImpl.h:
+        (FrameData):
+        (CCLayerTreeHostImpl):
+
 2012-06-08  Antonio Gomes  <agomes@rim.com>
 
         EventHandler shouldn't schedule the fake mousemove event timer when scrolling on devices that don't have a mouse
index 5b13e1b..a416301 100644 (file)
@@ -261,12 +261,7 @@ void CCLayerTreeHostImpl::calculateRenderSurfaceLayerList(CCLayerList& renderSur
     }
 }
 
-static inline bool shouldDrawLayer(CCLayerImpl* layer)
-{
-    return !layer->visibleLayerRect().isEmpty() && !layer->scissorRect().isEmpty();
-}
-
-bool CCLayerTreeHostImpl::calculateRenderPasses(CCRenderPassList& passes, CCLayerList& renderSurfaceLayerList)
+bool CCLayerTreeHostImpl::calculateRenderPasses(CCRenderPassList& passes, CCLayerList& renderSurfaceLayerList, CCLayerList& willDrawLayers)
 {
     ASSERT(passes.isEmpty());
 
@@ -310,8 +305,10 @@ bool CCLayerTreeHostImpl::calculateRenderPasses(CCRenderPassList& passes, CCLaye
         if (it.representsContributingRenderSurface() && !it->renderSurface()->scissorRect().isEmpty()) {
             CCRenderPass* contributingRenderPass = surfacePassMap.get(it->renderSurface());
             pass->appendQuadsForRenderSurfaceLayer(*it, contributingRenderPass, &occlusionTracker);
-        } else if (it.representsItself() && shouldDrawLayer(*it)) {
+        } else if (it.representsItself() && !occlusionTracker.occluded(*it, it->visibleLayerRect()) && !it->visibleLayerRect().isEmpty() && !it->scissorRect().isEmpty()) {
             it->willDraw(m_layerRenderer.get(), context());
+            willDrawLayers.append(*it);
+
             pass->appendQuadsForLayer(*it, &occlusionTracker, hadMissingTiles);
         }
 
@@ -384,8 +381,9 @@ bool CCLayerTreeHostImpl::prepareToDraw(FrameData& frame)
 
     frame.renderPasses.clear();
     frame.renderSurfaceLayerList.clear();
+    frame.willDrawLayers.clear();
 
-    if (!calculateRenderPasses(frame.renderPasses, frame.renderSurfaceLayerList))
+    if (!calculateRenderPasses(frame.renderPasses, frame.renderSurfaceLayerList, frame.willDrawLayers))
         return false;
 
     // If we return true, then we expect drawLayers() to be called before this function is called again.
@@ -436,13 +434,8 @@ void CCLayerTreeHostImpl::drawLayers(const FrameData& frame)
 
 void CCLayerTreeHostImpl::didDrawAllLayers(const FrameData& frame)
 {
-    typedef CCLayerIterator<CCLayerImpl, Vector<CCLayerImpl*>, CCRenderSurface, CCLayerIteratorActions::BackToFront> CCLayerIteratorType;
-
-    CCLayerIteratorType end = CCLayerIteratorType::end(&frame.renderSurfaceLayerList);
-    for (CCLayerIteratorType it = CCLayerIteratorType::begin(&frame.renderSurfaceLayerList); it != end; ++it) {
-        if (it.representsItself() && shouldDrawLayer(*it))
-            it->didDraw();
-    }
+    for (size_t i = 0; i < frame.willDrawLayers.size(); ++i)
+        frame.willDrawLayers[i]->didDraw();
 }
 
 void CCLayerTreeHostImpl::finishAllRendering()
index c740a66..46191f1 100644 (file)
@@ -87,6 +87,7 @@ public:
     struct FrameData {
         CCRenderPassList renderPasses;
         CCLayerList renderSurfaceLayerList;
+        CCLayerList willDrawLayers;
     };
 
     // Virtual for testing.
@@ -200,7 +201,7 @@ private:
     // Returns false if the frame should not be displayed. This function should
     // only be called from prepareToDraw, as didDrawAllLayers must be called
     // if this helper function is called.
-    bool calculateRenderPasses(CCRenderPassList&, CCLayerList& renderSurfaceLayerList);
+    bool calculateRenderPasses(CCRenderPassList&, CCLayerList& renderSurfaceLayerList, CCLayerList& willDrawLayers);
     void animateLayersRecursive(CCLayerImpl*, double monotonicTime, double wallClockTime, CCAnimationEventsVector*, bool& didAnimate, bool& needsAnimateLayers);
     void setBackgroundTickingEnabled(bool);
     IntSize contentSize() const;
index dee8fe8..a40d2ee 100644 (file)
@@ -1,3 +1,12 @@
+2012-06-08  Dana Jansens  <danakj@chromium.org>
+
+        [chromium] Skip willDraw() and didDraw() on fully occluded layers
+        https://bugs.webkit.org/show_bug.cgi?id=88435
+
+        Reviewed by Adrienne Walker.
+
+        * tests/CCLayerTreeHostImplTest.cpp:
+
 2012-06-08  James Robinson  <jamesr@chromium.org>
 
         [chromium] Clean up some unnecessary LayerChromium.h includes
index 1657c33..039e0cd 100644 (file)
@@ -468,7 +468,12 @@ protected:
     {
         setAnchorPoint(FloatPoint(0, 0));
         setBounds(IntSize(10, 10));
+        setContentBounds(IntSize(10, 10));
         setDrawsContent(true);
+        setSkipsDraw(false);
+
+        OwnPtr<CCLayerTilingData> tiler = CCLayerTilingData::create(IntSize(100, 100), CCLayerTilingData::HasBorderTexels);
+        setTilingData(*tiler.get());
     }
 
 private:
@@ -521,6 +526,42 @@ TEST_F(CCLayerTreeHostImplTest, didDrawNotCalledOnHiddenLayer)
     EXPECT_FALSE(layer->visibleLayerRect().isEmpty());
 }
 
+TEST_F(CCLayerTreeHostImplTest, willDrawNotCalledOnOccludedLayer)
+{
+    // Make the viewport large so that we can have large layers that get considered for occlusion (small layers do not).
+    IntSize bigSize(1000, 1000);
+    m_hostImpl->setViewportSize(bigSize);
+
+    m_hostImpl->setRootLayer(DidDrawCheckLayer::create(0));
+    DidDrawCheckLayer* root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer());
+
+    root->addChild(DidDrawCheckLayer::create(1));
+    DidDrawCheckLayer* occludedLayer = static_cast<DidDrawCheckLayer*>(root->children()[0].get());
+
+    root->addChild(DidDrawCheckLayer::create(2));
+    DidDrawCheckLayer* topLayer = static_cast<DidDrawCheckLayer*>(root->children()[1].get());
+    // This layer covers the occludedLayer above. Make this layer large so it can occlude.
+    topLayer->setBounds(bigSize);
+    topLayer->setContentBounds(bigSize);
+    topLayer->setOpaque(true);
+
+    CCLayerTreeHostImpl::FrameData frame;
+
+    EXPECT_FALSE(occludedLayer->willDrawCalled());
+    EXPECT_FALSE(occludedLayer->didDrawCalled());
+    EXPECT_FALSE(topLayer->willDrawCalled());
+    EXPECT_FALSE(topLayer->didDrawCalled());
+
+    EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
+    m_hostImpl->drawLayers(frame);
+    m_hostImpl->didDrawAllLayers(frame);
+
+    EXPECT_FALSE(occludedLayer->willDrawCalled());
+    EXPECT_FALSE(occludedLayer->didDrawCalled());
+    EXPECT_TRUE(topLayer->willDrawCalled());
+    EXPECT_TRUE(topLayer->didDrawCalled());
+}
+
 TEST_F(CCLayerTreeHostImplTest, didDrawCalledOnAllLayers)
 {
     m_hostImpl->setRootLayer(DidDrawCheckLayer::create(0));