[chromium] Use CCOcclusionTracker for draw culling
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 13 Mar 2012 20:14:39 +0000 (20:14 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 13 Mar 2012 20:14:39 +0000 (20:14 +0000)
https://bugs.webkit.org/show_bug.cgi?id=80743

Patch by Dana Jansens <danakj@chromium.org> on 2012-03-13
Reviewed by Adrienne Walker.

Source/WebCore:

In this CL we enable the use of CCOcclusionTracker for draw-side
culling. This means moving from a per-quad culling model to a
per-layer model.

When calculating RenderPasses, we construct the set of passes,
then iterate over layers in front-to-back order. We make
CCQuadCuller instantiable, and pass it to the layer
appendQuads() methods instead of the bare list, where it can
filter quads before the end up in the list.

Covered by existing tests.

* platform/graphics/chromium/LayerRendererChromium.cpp:
(WebCore::LayerRendererChromium::drawRenderPass):
* platform/graphics/chromium/LayerRendererChromium.h:
* platform/graphics/chromium/cc/CCCanvasLayerImpl.cpp:
(WebCore::CCCanvasLayerImpl::appendQuads):
* platform/graphics/chromium/cc/CCCanvasLayerImpl.h:
(CCCanvasLayerImpl):
* platform/graphics/chromium/cc/CCLayerImpl.cpp:
(WebCore::CCLayerImpl::appendQuads):
(WebCore::CCLayerImpl::appendGutterQuads):
(WebCore::CCLayerImpl::appendDebugBorderQuad):
* platform/graphics/chromium/cc/CCLayerImpl.h:
(WebCore):
(CCLayerImpl):
* platform/graphics/chromium/cc/CCLayerTreeHostImpl.cpp:
(WebCore::CCLayerTreeHostImpl::calculateRenderPasses):
(WebCore::CCLayerTreeHostImpl::drawLayers):
* platform/graphics/chromium/cc/CCLayerTreeHostImpl.h:
(CCLayerTreeHostImpl):
* platform/graphics/chromium/cc/CCPluginLayerImpl.cpp:
(WebCore::CCPluginLayerImpl::appendQuads):
* platform/graphics/chromium/cc/CCPluginLayerImpl.h:
(CCPluginLayerImpl):
* platform/graphics/chromium/cc/CCQuadCuller.cpp:
(WebCore::CCQuadCuller::CCQuadCuller):
(WebCore::CCQuadCuller::append):
* platform/graphics/chromium/cc/CCQuadCuller.h:
(WebCore):
(CCQuadCuller):
* platform/graphics/chromium/cc/CCRenderPass.cpp:
(WebCore::CCRenderPass::appendQuadsForLayer):
* platform/graphics/chromium/cc/CCRenderPass.h:
(WebCore):
(CCQuadList):
(WebCore::CCQuadList::backToFrontBegin):
(WebCore::CCQuadList::backToFrontEnd):
(CCRenderPass):
* platform/graphics/chromium/cc/CCScrollbarLayerImpl.cpp:
(WebCore::CCScrollbarLayerImpl::appendQuads):
* platform/graphics/chromium/cc/CCScrollbarLayerImpl.h:
(CCScrollbarLayerImpl):
* platform/graphics/chromium/cc/CCSolidColorLayerImpl.cpp:
(WebCore::CCSolidColorLayerImpl::appendQuads):
* platform/graphics/chromium/cc/CCSolidColorLayerImpl.h:
(CCSolidColorLayerImpl):
* platform/graphics/chromium/cc/CCTiledLayerImpl.cpp:
(WebCore::CCTiledLayerImpl::appendQuads):
* platform/graphics/chromium/cc/CCTiledLayerImpl.h:
(CCTiledLayerImpl):
* platform/graphics/chromium/cc/CCVideoLayerImpl.cpp:
(WebCore::CCVideoLayerImpl::appendQuads):
* platform/graphics/chromium/cc/CCVideoLayerImpl.h:
(CCVideoLayerImpl):

Source/WebKit/chromium:

* WebKit.gypi:
* tests/CCLayerTreeHostImplTest.cpp:
(WebKit::BlendStateCheckLayer::appendQuads):
* tests/CCQuadCullerTest.cpp:
(TestCCOcclusionTrackerImpl):
(WebCore::TestCCOcclusionTrackerImpl::TestCCOcclusionTrackerImpl):
(WebCore::TestCCOcclusionTrackerImpl::layerScissorRectInTargetSurface):
(WebCore::makeLayer):
(WebCore::appendQuads):
(WebCore):
(WebCore::TEST):
* tests/CCSolidColorLayerImplTest.cpp:
(CCLayerTestCommon::TEST):
* tests/CCTiledLayerImplTest.cpp:
(CCLayerTestCommon::TEST):
(CCLayerTestCommon::getQuads):
* tests/MockCCQuadCuller.h: Added.
(WebCore):
(MockCCQuadCuller):
(WebCore::MockCCQuadCuller::MockCCQuadCuller):
(WebCore::MockCCQuadCuller::append):
(WebCore::MockCCQuadCuller::quadList):

LayoutTests:

* platform/chromium-linux/compositing/direct-image-compositing-expected.png:
* platform/chromium-linux/compositing/geometry/vertical-scroll-composited-expected.png:
* platform/chromium-linux/platform/chromium/compositing/huge-layer-rotated-expected.png:
* platform/chromium/test_expectations.txt:

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

35 files changed:
LayoutTests/ChangeLog
LayoutTests/platform/chromium-linux/compositing/direct-image-compositing-expected.png
LayoutTests/platform/chromium-linux/compositing/geometry/vertical-scroll-composited-expected.png
LayoutTests/platform/chromium-linux/platform/chromium/compositing/huge-layer-rotated-expected.png
LayoutTests/platform/chromium/test_expectations.txt
Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp
Source/WebCore/platform/graphics/chromium/LayerRendererChromium.h
Source/WebCore/platform/graphics/chromium/cc/CCCanvasLayerImpl.cpp
Source/WebCore/platform/graphics/chromium/cc/CCCanvasLayerImpl.h
Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.cpp
Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.h
Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostImpl.cpp
Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostImpl.h
Source/WebCore/platform/graphics/chromium/cc/CCPluginLayerImpl.cpp
Source/WebCore/platform/graphics/chromium/cc/CCPluginLayerImpl.h
Source/WebCore/platform/graphics/chromium/cc/CCQuadCuller.cpp
Source/WebCore/platform/graphics/chromium/cc/CCQuadCuller.h
Source/WebCore/platform/graphics/chromium/cc/CCRenderPass.cpp
Source/WebCore/platform/graphics/chromium/cc/CCRenderPass.h
Source/WebCore/platform/graphics/chromium/cc/CCScrollbarLayerImpl.cpp
Source/WebCore/platform/graphics/chromium/cc/CCScrollbarLayerImpl.h
Source/WebCore/platform/graphics/chromium/cc/CCSolidColorLayerImpl.cpp
Source/WebCore/platform/graphics/chromium/cc/CCSolidColorLayerImpl.h
Source/WebCore/platform/graphics/chromium/cc/CCTiledLayerImpl.cpp
Source/WebCore/platform/graphics/chromium/cc/CCTiledLayerImpl.h
Source/WebCore/platform/graphics/chromium/cc/CCVideoLayerImpl.cpp
Source/WebCore/platform/graphics/chromium/cc/CCVideoLayerImpl.h
Source/WebKit/chromium/ChangeLog
Source/WebKit/chromium/WebKit.gypi
Source/WebKit/chromium/tests/CCLayerTreeHostImplTest.cpp
Source/WebKit/chromium/tests/CCQuadCullerTest.cpp
Source/WebKit/chromium/tests/CCSolidColorLayerImplTest.cpp
Source/WebKit/chromium/tests/CCTiledLayerImplTest.cpp
Source/WebKit/chromium/tests/MockCCQuadCuller.h [new file with mode: 0644]

index 1d3eef9..b3268f1 100644 (file)
@@ -1,3 +1,15 @@
+2012-03-13  Dana Jansens  <danakj@chromium.org>
+
+        [chromium] Use CCOcclusionTracker for draw culling
+        https://bugs.webkit.org/show_bug.cgi?id=80743
+
+        Reviewed by Adrienne Walker.
+
+        * platform/chromium-linux/compositing/direct-image-compositing-expected.png:
+        * platform/chromium-linux/compositing/geometry/vertical-scroll-composited-expected.png:
+        * platform/chromium-linux/platform/chromium/compositing/huge-layer-rotated-expected.png:
+        * platform/chromium/test_expectations.txt:
+
 2012-03-12  Antonio Gomes  <agomes@rim.com>
 
         Convert nodesFromRect tests to use Internals interface
index 1afd8dc..091a135 100644 (file)
Binary files a/LayoutTests/platform/chromium-linux/compositing/direct-image-compositing-expected.png and b/LayoutTests/platform/chromium-linux/compositing/direct-image-compositing-expected.png differ
index 6563128..84da22f 100644 (file)
Binary files a/LayoutTests/platform/chromium-linux/compositing/geometry/vertical-scroll-composited-expected.png and b/LayoutTests/platform/chromium-linux/compositing/geometry/vertical-scroll-composited-expected.png differ
index c1dbd82..a808363 100644 (file)
Binary files a/LayoutTests/platform/chromium-linux/platform/chromium/compositing/huge-layer-rotated-expected.png and b/LayoutTests/platform/chromium-linux/platform/chromium/compositing/huge-layer-rotated-expected.png differ
index 3bc1cf4..093e5f8 100644 (file)
@@ -3883,6 +3883,11 @@ BUG_SENORBLANCO DEBUG : css3/filters/composited-during-animation-layertree.html
 // New test, crashing as of r110224:110226.
 BUG_SENORBLANCO : fast/events/input-focus-no-duplicate-events.html = CRASH
 
+// May require rebaseline after this patch lands.
+BUGWK80743 WIN MAC : compositing/geometry/vertical-scroll-composited.html = PASS IMAGE
+BUGWK80743 WIN MAC : compositing/direct-image-compositing.html = PASS IMAGE
+BUGWK80743 WIN MAC : platform/chromium/compositing/huge-layer-rotated.html = PASS IMAGE
+
 BUGWK80563 : css3/filters/effect-combined-hw.html = PASS IMAGE
 BUGWK80563 : css3/filters/effect-hue-rotate-hw.html = PASS IMAGE
 BUGWK80563 : css3/filters/effect-opacity-hw.html = PASS IMAGE
index dac3a40..1ea0639 100644 (file)
@@ -1,3 +1,76 @@
+2012-03-13  Dana Jansens  <danakj@chromium.org>
+
+        [chromium] Use CCOcclusionTracker for draw culling
+        https://bugs.webkit.org/show_bug.cgi?id=80743
+
+        Reviewed by Adrienne Walker.
+
+        In this CL we enable the use of CCOcclusionTracker for draw-side
+        culling. This means moving from a per-quad culling model to a
+        per-layer model.
+
+        When calculating RenderPasses, we construct the set of passes,
+        then iterate over layers in front-to-back order. We make
+        CCQuadCuller instantiable, and pass it to the layer
+        appendQuads() methods instead of the bare list, where it can
+        filter quads before the end up in the list.
+
+        Covered by existing tests.
+
+        * platform/graphics/chromium/LayerRendererChromium.cpp:
+        (WebCore::LayerRendererChromium::drawRenderPass):
+        * platform/graphics/chromium/LayerRendererChromium.h:
+        * platform/graphics/chromium/cc/CCCanvasLayerImpl.cpp:
+        (WebCore::CCCanvasLayerImpl::appendQuads):
+        * platform/graphics/chromium/cc/CCCanvasLayerImpl.h:
+        (CCCanvasLayerImpl):
+        * platform/graphics/chromium/cc/CCLayerImpl.cpp:
+        (WebCore::CCLayerImpl::appendQuads):
+        (WebCore::CCLayerImpl::appendGutterQuads):
+        (WebCore::CCLayerImpl::appendDebugBorderQuad):
+        * platform/graphics/chromium/cc/CCLayerImpl.h:
+        (WebCore):
+        (CCLayerImpl):
+        * platform/graphics/chromium/cc/CCLayerTreeHostImpl.cpp:
+        (WebCore::CCLayerTreeHostImpl::calculateRenderPasses):
+        (WebCore::CCLayerTreeHostImpl::drawLayers):
+        * platform/graphics/chromium/cc/CCLayerTreeHostImpl.h:
+        (CCLayerTreeHostImpl):
+        * platform/graphics/chromium/cc/CCPluginLayerImpl.cpp:
+        (WebCore::CCPluginLayerImpl::appendQuads):
+        * platform/graphics/chromium/cc/CCPluginLayerImpl.h:
+        (CCPluginLayerImpl):
+        * platform/graphics/chromium/cc/CCQuadCuller.cpp:
+        (WebCore::CCQuadCuller::CCQuadCuller):
+        (WebCore::CCQuadCuller::append):
+        * platform/graphics/chromium/cc/CCQuadCuller.h:
+        (WebCore):
+        (CCQuadCuller):
+        * platform/graphics/chromium/cc/CCRenderPass.cpp:
+        (WebCore::CCRenderPass::appendQuadsForLayer):
+        * platform/graphics/chromium/cc/CCRenderPass.h:
+        (WebCore):
+        (CCQuadList):
+        (WebCore::CCQuadList::backToFrontBegin):
+        (WebCore::CCQuadList::backToFrontEnd):
+        (CCRenderPass):
+        * platform/graphics/chromium/cc/CCScrollbarLayerImpl.cpp:
+        (WebCore::CCScrollbarLayerImpl::appendQuads):
+        * platform/graphics/chromium/cc/CCScrollbarLayerImpl.h:
+        (CCScrollbarLayerImpl):
+        * platform/graphics/chromium/cc/CCSolidColorLayerImpl.cpp:
+        (WebCore::CCSolidColorLayerImpl::appendQuads):
+        * platform/graphics/chromium/cc/CCSolidColorLayerImpl.h:
+        (CCSolidColorLayerImpl):
+        * platform/graphics/chromium/cc/CCTiledLayerImpl.cpp:
+        (WebCore::CCTiledLayerImpl::appendQuads):
+        * platform/graphics/chromium/cc/CCTiledLayerImpl.h:
+        (CCTiledLayerImpl):
+        * platform/graphics/chromium/cc/CCVideoLayerImpl.cpp:
+        (WebCore::CCVideoLayerImpl::appendQuads):
+        * platform/graphics/chromium/cc/CCVideoLayerImpl.h:
+        (CCVideoLayerImpl):
+
 2012-03-13  Adam Barth  <abarth@webkit.org> && Benjamin Poulain  <bpoulain@apple.com>
 
         Always enable ENABLE(CLIENT_BASED_GEOLOCATION)
index 9ece89d..b162eab 100644 (file)
@@ -412,8 +412,8 @@ void LayerRendererChromium::drawRenderPass(const CCRenderPass* renderPass)
     clearRenderSurface(renderSurface, m_defaultRenderSurface, renderPass->surfaceDamageRect());
 
     const CCQuadList& quadList = renderPass->quadList();
-    for (size_t i = 0; i < quadList.size(); ++i)
-        drawQuad(quadList[i].get(), renderPass->surfaceDamageRect());
+    for (CCQuadList::constBackToFrontIterator it = quadList.backToFrontBegin(); it != quadList.backToFrontEnd(); ++it)
+        drawQuad(it->get(), renderPass->surfaceDamageRect());
 }
 
 void LayerRendererChromium::drawQuad(const CCDrawQuad* quad, const FloatRect& surfaceDamageRect)
index 91fcf6a..a6876e5 100644 (file)
@@ -41,6 +41,7 @@
 #include "TrackingTextureAllocator.h"
 #include "VideoLayerChromium.h"
 #include "cc/CCCanvasLayerImpl.h"
+#include "cc/CCDrawQuad.h"
 #include "cc/CCHeadsUpDisplay.h"
 #include "cc/CCLayerTreeHost.h"
 #include "cc/CCPluginLayerImpl.h"
index 2bb3eff..144e579 100644 (file)
@@ -33,6 +33,7 @@
 #include "LayerRendererChromium.h"
 #include "cc/CCCanvasDrawQuad.h"
 #include "cc/CCProxy.h"
+#include "cc/CCQuadCuller.h"
 #include <wtf/text/WTFString.h>
 
 namespace WebCore {
@@ -49,7 +50,7 @@ CCCanvasLayerImpl::~CCCanvasLayerImpl()
 {
 }
 
-void CCCanvasLayerImpl::appendQuads(CCQuadList& quadList, const CCSharedQuadState* sharedQuadState)
+void CCCanvasLayerImpl::appendQuads(CCQuadCuller& quadList, const CCSharedQuadState* sharedQuadState)
 {
     IntRect quadRect(IntPoint(), bounds());
     quadList.append(CCCanvasDrawQuad::create(sharedQuadState, quadRect, m_textureId, m_hasAlpha, m_premultipliedAlpha));
index c96af24..a9eb860 100644 (file)
@@ -40,7 +40,7 @@ public:
     }
     virtual ~CCCanvasLayerImpl();
 
-    virtual void appendQuads(CCQuadList&, const CCSharedQuadState*);
+    virtual void appendQuads(CCQuadCuller&, const CCSharedQuadState*);
 
     typedef ProgramBinding<VertexShaderPosTex, FragmentShaderRGBATexFlipAlpha> Program;
 
index 8f60780..4fce76b 100644 (file)
@@ -35,6 +35,7 @@
 #include "cc/CCDebugBorderDrawQuad.h"
 #include "cc/CCLayerAnimationControllerImpl.h"
 #include "cc/CCLayerSorter.h"
+#include "cc/CCQuadCuller.h"
 #include "cc/CCSolidColorDrawQuad.h"
 #include <wtf/text/WTFString.h>
 
@@ -133,12 +134,12 @@ PassOwnPtr<CCSharedQuadState> CCLayerImpl::createSharedQuadState() const
     return CCSharedQuadState::create(quadTransform(), drawTransform(), visibleLayerRect(), layerClipRect, drawOpacity(), opaque());
 }
 
-void CCLayerImpl::appendQuads(CCQuadList& quadList, const CCSharedQuadState* sharedQuadState)
+void CCLayerImpl::appendQuads(CCQuadCuller& quadList, const CCSharedQuadState* sharedQuadState)
 {
     appendGutterQuads(quadList, sharedQuadState);
 }
 
-void CCLayerImpl::appendGutterQuads(CCQuadList& quadList, const CCSharedQuadState* sharedQuadState)
+void CCLayerImpl::appendGutterQuads(CCQuadCuller& quadList, const CCSharedQuadState* sharedQuadState)
 {
     if (!backgroundCoversViewport() || !backgroundColor().isValid())
         return;
@@ -170,7 +171,7 @@ void CCLayerImpl::appendGutterQuads(CCQuadList& quadList, const CCSharedQuadStat
     }
 }
 
-void CCLayerImpl::appendDebugBorderQuad(CCQuadList& quadList, const CCSharedQuadState* sharedQuadState) const
+void CCLayerImpl::appendDebugBorderQuad(CCQuadCuller& quadList, const CCSharedQuadState* sharedQuadState) const
 {
     if (!hasDebugBorders())
         return;
index f1c7b4e..8d33b64 100644 (file)
@@ -34,8 +34,8 @@
 #include "TextStream.h"
 #include "TransformationMatrix.h"
 #include "cc/CCLayerAnimationControllerImpl.h"
-#include "cc/CCRenderPass.h"
 #include "cc/CCRenderSurface.h"
+#include "cc/CCSharedQuadState.h"
 #include <wtf/OwnPtr.h>
 #include <wtf/PassRefPtr.h>
 #include <wtf/RefCounted.h>
@@ -44,6 +44,7 @@
 namespace WebCore {
 
 class CCLayerSorter;
+class CCQuadCuller;
 class LayerChromium;
 class LayerRendererChromium;
 
@@ -83,9 +84,9 @@ public:
 
     PassOwnPtr<CCSharedQuadState> createSharedQuadState() const;
     virtual void willDraw(LayerRendererChromium*) { }
-    virtual void appendQuads(CCQuadList&, const CCSharedQuadState*);
+    virtual void appendQuads(CCQuadCuller&, const CCSharedQuadState*);
     virtual void didDraw() { }
-    void appendDebugBorderQuad(CCQuadList&, const CCSharedQuadState*) const;
+    void appendDebugBorderQuad(CCQuadCuller&, const CCSharedQuadState*) const;
 
     void unreserveContentsTexture();
     virtual void bindContentsTexture(LayerRendererChromium*);
@@ -231,7 +232,7 @@ protected:
     // Transformation used to transform quads provided in appendQuads.
     virtual TransformationMatrix quadTransform() const;
 
-    void appendGutterQuads(CCQuadList&, const CCSharedQuadState*);
+    void appendGutterQuads(CCQuadCuller&, const CCSharedQuadState*);
 
 private:
     void setParent(CCLayerImpl* parent) { m_parent = parent; }
index 002e782..5c7f565 100644 (file)
@@ -221,6 +221,8 @@ static FloatRect damageInSurfaceSpace(CCLayerImpl* renderSurfaceLayer, const Flo
 
 void CCLayerTreeHostImpl::calculateRenderPasses(CCRenderPassList& passes, CCLayerList& renderSurfaceLayerList)
 {
+    TRACE_EVENT1("webkit", "CCLayerTreeHostImpl::calculateRenderPasses", "renderSurfaceLayerList.size()", static_cast<long long unsigned>(renderSurfaceLayerList.size()));
+
     renderSurfaceLayerList.append(rootLayer());
 
     if (!rootLayer()->renderSurface())
@@ -240,6 +242,8 @@ void CCLayerTreeHostImpl::calculateRenderPasses(CCRenderPassList& passes, CCLaye
         trackDamageForAllSurfaces(rootLayer(), renderSurfaceLayerList);
     m_rootDamageRect = rootLayer()->renderSurface()->damageTracker()->currentDamageRect();
 
+    // Create the render passes in dependency order.
+    HashMap<CCRenderSurface*, CCRenderPass*> surfacePassMap;
     for (int surfaceIndex = renderSurfaceLayerList.size() - 1; surfaceIndex >= 0 ; --surfaceIndex) {
         CCLayerImpl* renderSurfaceLayer = renderSurfaceLayerList[surfaceIndex];
         CCRenderSurface* renderSurface = renderSurfaceLayer->renderSurface();
@@ -251,36 +255,48 @@ void CCLayerTreeHostImpl::calculateRenderPasses(CCRenderPassList& passes, CCLaye
             surfaceDamageRect = damageInSurfaceSpace(renderSurfaceLayer, m_rootDamageRect);
         pass->setSurfaceDamageRect(surfaceDamageRect);
 
-        const CCLayerList& layerList = renderSurface->layerList();
-        for (unsigned layerIndex = 0; layerIndex < layerList.size(); ++layerIndex) {
-            CCLayerImpl* layer = layerList[layerIndex];
-            if (layer->visibleLayerRect().isEmpty())
-                continue;
-
-            if (CCLayerTreeHostCommon::renderSurfaceContributesToTarget(layer, renderSurfaceLayer->id())) {
-                pass->appendQuadsForRenderSurfaceLayer(layer);
-                continue;
-            }
-
-            layer->willDraw(m_layerRenderer.get());
-            pass->appendQuadsForLayer(layer);
-        }
-
+        surfacePassMap.add(renderSurface, pass.get());
         passes.append(pass.release());
     }
-}
-
-void CCLayerTreeHostImpl::optimizeRenderPasses(CCRenderPassList& passes)
-{
-    TRACE_EVENT1("webkit", "CCLayerTreeHostImpl::optimizeRenderPasses", "passes.size()", static_cast<long long unsigned>(passes.size()));
-
-    bool haveDamageRect = layerRendererCapabilities().usingPartialSwap;
 
     // FIXME: compute overdraw metrics only occasionally, not every frame.
     CCOverdrawCounts overdrawCounts;
-    for (unsigned i = 0; i < passes.size(); ++i) {
-        FloatRect damageRect = passes[i]->surfaceDamageRect();
-        passes[i]->optimizeQuads(haveDamageRect, damageRect, &overdrawCounts);
+
+    IntRect scissorRect;
+    if (layerRendererCapabilities().usingPartialSwap)
+        scissorRect = enclosingIntRect(m_rootDamageRect);
+    else
+        scissorRect = IntRect(IntPoint(), viewportSize());
+    CCOcclusionTrackerImpl occlusionTracker(scissorRect);
+
+    // Add quads to the Render passes in FrontToBack order to allow for testing occlusion and performing culling during the tree walk.
+    typedef CCLayerIterator<CCLayerImpl, Vector<CCLayerImpl*>, CCRenderSurface, CCLayerIteratorActions::FrontToBack> CCLayerIteratorType;
+
+    CCLayerIteratorType end = CCLayerIteratorType::end(&renderSurfaceLayerList);
+    for (CCLayerIteratorType it = CCLayerIteratorType::begin(&renderSurfaceLayerList); it != end; ++it) {
+        CCRenderSurface* renderSurface = it.targetRenderSurfaceLayer()->renderSurface();
+
+        if (it.representsItself())
+            occlusionTracker.enterTargetRenderSurface(renderSurface);
+        else if (it.representsTargetRenderSurface())
+            occlusionTracker.finishedTargetRenderSurface(*it, renderSurface);
+        else
+            occlusionTracker.leaveToTargetRenderSurface(renderSurface);
+
+        if (it.representsTargetRenderSurface())
+            continue;
+        if (it->visibleLayerRect().isEmpty())
+            continue;
+
+        CCRenderPass* pass = surfacePassMap.get(renderSurface);
+        if (it.representsContributingRenderSurface()) {
+            pass->appendQuadsForRenderSurfaceLayer(*it);
+            continue;
+        }
+
+        it->willDraw(m_layerRenderer.get());
+        pass->appendQuadsForLayer(*it, &occlusionTracker, &overdrawCounts);
+        occlusionTracker.markOccludedBehindLayer(*it);
     }
 
     float normalization = 1000.f / (m_layerRenderer->viewportWidth() * m_layerRenderer->viewportHeight());
@@ -338,8 +354,6 @@ void CCLayerTreeHostImpl::drawLayers()
     CCLayerList renderSurfaceLayerList;
     calculateRenderPasses(passes, renderSurfaceLayerList);
 
-    optimizeRenderPasses(passes);
-
     m_layerRenderer->beginDrawingFrame();
     for (size_t i = 0; i < passes.size(); ++i)
         m_layerRenderer->drawRenderPass(passes[i].get());
index 1cfd0fb..dc05da8 100644 (file)
@@ -156,7 +156,6 @@ private:
     void updateMaxScrollPosition();
     void trackDamageForAllSurfaces(CCLayerImpl* rootDrawLayer, const CCLayerList& renderSurfaceLayerList);
     void calculateRenderPasses(CCRenderPassList&, CCLayerList& renderSurfaceLayerList);
-    void optimizeRenderPasses(CCRenderPassList&);
     void animateLayersRecursive(CCLayerImpl*, double monotonicTime, double wallClockTime, CCAnimationEventsVector&, bool& didAnimate, bool& needsAnimateLayers);
     IntSize contentSize() const;
     void sendDidLoseContextRecursive(CCLayerImpl*);
index 7453816..4b14114 100644 (file)
@@ -34,6 +34,7 @@
 #include "LayerRendererChromium.h"
 #include "cc/CCPluginDrawQuad.h"
 #include "cc/CCProxy.h"
+#include "cc/CCQuadCuller.h"
 #include <wtf/text/WTFString.h>
 
 namespace WebCore {
@@ -90,7 +91,7 @@ void CCPluginLayerImpl::willDraw(LayerRendererChromium* layerRenderer)
     }
 }
 
-void CCPluginLayerImpl::appendQuads(CCQuadList& quadList, const CCSharedQuadState* sharedQuadState)
+void CCPluginLayerImpl::appendQuads(CCQuadCuller& quadList, const CCSharedQuadState* sharedQuadState)
 {
     IntRect quadRect(IntPoint(), bounds());
     quadList.append(CCPluginDrawQuad::create(sharedQuadState, quadRect, m_uvRect, m_textureId, m_flipped, m_ioSurfaceWidth, m_ioSurfaceHeight, m_ioSurfaceTextureId));
index 370e09d..969b336 100644 (file)
@@ -42,7 +42,7 @@ public:
     virtual ~CCPluginLayerImpl();
 
     virtual void willDraw(LayerRendererChromium*);
-    virtual void appendQuads(CCQuadList&, const CCSharedQuadState*);
+    virtual void appendQuads(CCQuadCuller&, const CCSharedQuadState*);
 
     typedef ProgramBinding<VertexShaderPosTexStretch, FragmentShaderRGBATexAlpha> Program;
     typedef ProgramBinding<VertexShaderPosTexStretch, FragmentShaderRGBATexFlipAlpha> ProgramFlip;
index 1c4a499..f7b56b9 100644 (file)
 
 using namespace std;
 
-namespace std {
-
-// Specialize for OwnPtr<CCDrawQuad> since Vector doesn't know how to reverse a Vector of OwnPtr<T> in general.
-template<>
-void swap(OwnPtr<WebCore::CCDrawQuad>& a, OwnPtr<WebCore::CCDrawQuad>& b)
-{
-    a.swap(b);
-}
-
-}
-
 namespace WebCore {
 
-// Determines what portion of rect, if any, is visible (not occluded by region). If
-// the resulting visible region is not rectangular, we just return the original rect.
-static IntRect rectSubtractRegion(const Region& region, const IntRect& rect)
+CCQuadCuller::CCQuadCuller(CCQuadList& quadList, CCLayerImpl* layer, CCOcclusionTrackerImpl* occlusionTracker, CCOverdrawCounts* overdrawCounts)
+    : m_quadList(quadList)
+    , m_layer(layer)
+    , m_occlusionTracker(occlusionTracker)
+    , m_overdrawCounts(overdrawCounts)
 {
-    Region rectRegion(rect);
-    Region intersectRegion(intersect(region, rectRegion));
-
-    if (intersectRegion.isEmpty())
-        return rect;
-
-    // Test if intersectRegion = rectRegion, if so return empty rect.
-    rectRegion.subtract(intersectRegion);
-    IntRect boundsRect = rectRegion.bounds();
-    if (boundsRect.isEmpty())
-        return boundsRect;
-
-    // Test if rectRegion is still a rectangle. If it is, it will be identical to its bounds.
-    Region boundsRegion(boundsRect);
-    boundsRegion.subtract(rectRegion);
-    if (boundsRegion.isEmpty())
-        return boundsRect;
-
-    return rect;
 }
 
 static float wedgeProduct(const FloatPoint& p1, const FloatPoint& p2)
@@ -90,69 +62,40 @@ static float quadArea(const FloatQuad& quad)
                    wedgeProduct(quad.p4(), quad.p1())));
 }
 
-void CCQuadCuller::cullOccludedQuads(CCQuadList& quadList, bool haveDamageRect, const FloatRect& damageRect, CCOverdrawCounts* overdrawMetrics)
+void CCQuadCuller::append(PassOwnPtr<CCDrawQuad> passDrawQuad)
 {
-    if (!quadList.size())
-        return;
-
-    CCQuadList culledList;
-    culledList.reserveCapacity(quadList.size());
-
-    Region opaqueCoverageThusFar;
-
-    for (int i = quadList.size() - 1; i >= 0; --i) {
-        CCDrawQuad* drawQuad = quadList[i].get();
-
-        FloatRect floatTransformedRect = drawQuad->quadTransform().mapRect(FloatRect(drawQuad->quadRect()));
-        if (haveDamageRect)
-            floatTransformedRect.intersect(damageRect);
-        // Inflate rect to be tested to stay conservative.
-        IntRect transformedQuadRect(enclosingIntRect(floatTransformedRect));
-
-        IntRect transformedVisibleQuadRect = rectSubtractRegion(opaqueCoverageThusFar, transformedQuadRect);
-        bool keepQuad = !transformedVisibleQuadRect.isEmpty();
-
-        // See if we can reduce the number of pixels to draw by reducing the size of the draw
-        // quad - we do this by changing its visible rect.
-        bool didReduceQuadSize = false;
-        if (keepQuad) {
-            if (transformedVisibleQuadRect != transformedQuadRect && drawQuad->isLayerAxisAlignedIntRect()) {
-                drawQuad->setQuadVisibleRect(drawQuad->quadTransform().inverse().mapRect(transformedVisibleQuadRect));
-                didReduceQuadSize = true;
-            }
-
-            // When adding rect to opaque region, deflate it to stay conservative.
-            if (drawQuad->isLayerAxisAlignedIntRect() && !drawQuad->opaqueRect().isEmpty()) {
-                FloatRect floatOpaqueRect = drawQuad->quadTransform().mapRect(FloatRect(drawQuad->opaqueRect()));
-                opaqueCoverageThusFar.unite(Region(enclosedIntRect(floatOpaqueRect)));
-            }
-
-            culledList.append(quadList[i].release());
-        }
-
-        if (overdrawMetrics) {
+    OwnPtr<CCDrawQuad> drawQuad(passDrawQuad);
+    IntRect culledRect = m_occlusionTracker->unoccludedContentRect(m_layer, drawQuad->quadRect());
+    bool keepQuad = !culledRect.isEmpty();
+    if (keepQuad)
+        drawQuad->setQuadVisibleRect(culledRect);
+
+    // FIXME: Make a templated metrics class and move the logic out to there.
+    // Temporary code anyways, indented to make the diff clear.
+    {
+        if (m_overdrawCounts) {
             // We compute the area of the transformed quad, as this should be in pixels.
             float area = quadArea(drawQuad->quadTransform().mapQuad(FloatQuad(drawQuad->quadRect())));
             if (keepQuad) {
+                bool didReduceQuadSize = culledRect != drawQuad->quadRect();
                 if (didReduceQuadSize) {
                     float visibleQuadRectArea = quadArea(drawQuad->quadTransform().mapQuad(FloatQuad(drawQuad->quadVisibleRect())));
-                    overdrawMetrics->m_pixelsCulled += area - visibleQuadRectArea;
+                    m_overdrawCounts->m_pixelsCulled += area - visibleQuadRectArea;
                     area = visibleQuadRectArea;
                 }
                 IntRect visibleOpaqueRect(drawQuad->quadVisibleRect());
                 visibleOpaqueRect.intersect(drawQuad->opaqueRect());
                 FloatQuad visibleOpaqueQuad = drawQuad->quadTransform().mapQuad(FloatQuad(visibleOpaqueRect));
                 float opaqueArea = quadArea(visibleOpaqueQuad);
-                overdrawMetrics->m_pixelsDrawnOpaque += opaqueArea;
-                overdrawMetrics->m_pixelsDrawnTransparent += area - opaqueArea;
+                m_overdrawCounts->m_pixelsDrawnOpaque += opaqueArea;
+                m_overdrawCounts->m_pixelsDrawnTransparent += area - opaqueArea;
             } else
-                overdrawMetrics->m_pixelsCulled += area;
+                m_overdrawCounts->m_pixelsCulled += area;
         }
     }
-    quadList.clear(); // Release anything that remains.
 
-    culledList.reverse();
-    quadList.swap(culledList);
+    if (keepQuad)
+        m_quadList.append(drawQuad.release());
 }
 
 } // namespace WebCore
index 8958257..9c17aa8 100644 (file)
 #include "cc/CCRenderPass.h"
 
 namespace WebCore {
+class CCLayerImpl;
 
 class CCQuadCuller {
 public:
     // Passing 0 for CCOverdrawCounts* is valid, and disable the extra computation
     // done to estimate over draw statistics.
-    static void cullOccludedQuads(CCQuadList&, bool haveDamageRect, const FloatRect& damageRect, CCOverdrawCounts*);
+    CCQuadCuller(CCQuadList&, CCLayerImpl*, CCOcclusionTrackerImpl*, CCOverdrawCounts*);
+
+    virtual void append(PassOwnPtr<CCDrawQuad> passDrawQuad);
 
 private:
-    // Make non-instantiable.
-    CCQuadCuller() { }
+    CCQuadList& m_quadList;
+    CCLayerImpl* m_layer;
+    CCOcclusionTrackerImpl* m_occlusionTracker;
+    CCOverdrawCounts* m_overdrawCounts;
 };
 
 }
index bd877ec..674127e 100644 (file)
@@ -46,11 +46,13 @@ CCRenderPass::CCRenderPass(CCRenderSurface* targetSurface)
     ASSERT(m_targetSurface);
 }
 
-void CCRenderPass::appendQuadsForLayer(CCLayerImpl* layer)
+void CCRenderPass::appendQuadsForLayer(CCLayerImpl* layer, CCOcclusionTrackerImpl* occlusionTracker, CCOverdrawCounts* overdrawCounts)
 {
+    CCQuadCuller quadCuller(m_quadList, layer, occlusionTracker, overdrawCounts);
+
     OwnPtr<CCSharedQuadState> sharedQuadState = layer->createSharedQuadState();
-    layer->appendQuads(m_quadList, sharedQuadState.get());
-    layer->appendDebugBorderQuad(m_quadList, sharedQuadState.get());
+    layer->appendQuads(quadCuller, sharedQuadState.get());
+    layer->appendDebugBorderQuad(quadCuller, sharedQuadState.get());
     m_sharedQuadStateList.append(sharedQuadState.release());
 }
 
@@ -65,9 +67,4 @@ void CCRenderPass::appendQuadsForRenderSurfaceLayer(CCLayerImpl* layer)
     m_sharedQuadStateList.append(sharedQuadState.release());
 }
 
-void CCRenderPass::optimizeQuads(bool haveDamageRect, const FloatRect& damageRect, CCOverdrawCounts* overdraw)
-{
-    CCQuadCuller::cullOccludedQuads(m_quadList, haveDamageRect, damageRect, overdraw);
-}
-
 }
index 2affce5..09ac079 100644 (file)
@@ -27,6 +27,7 @@
 #define CCRenderPass_h
 
 #include "cc/CCDrawQuad.h"
+#include "cc/CCOcclusionTracker.h"
 #include <wtf/PassOwnPtr.h>
 #include <wtf/Vector.h>
 
@@ -36,7 +37,17 @@ class CCLayerImpl;
 class CCRenderSurface;
 class CCSharedQuadState;
 
-typedef Vector<OwnPtr<CCDrawQuad> > CCQuadList;
+// A list of CCDrawQuad objects, sorted internally in front-to-back order.
+class CCQuadList : public Vector<OwnPtr<CCDrawQuad> > {
+public:
+    typedef reverse_iterator backToFrontIterator;
+    typedef const_reverse_iterator constBackToFrontIterator;
+
+    inline backToFrontIterator backToFrontBegin() { return rbegin(); }
+    inline backToFrontIterator backToFrontEnd() { return rend(); }
+    inline constBackToFrontIterator backToFrontBegin() const { return rbegin(); }
+    inline constBackToFrontIterator backToFrontEnd() const { return rend(); }
+};
 
 struct CCOverdrawCounts {
     CCOverdrawCounts()
@@ -59,12 +70,9 @@ class CCRenderPass {
 public:
     static PassOwnPtr<CCRenderPass> create(CCRenderSurface*);
 
-    void appendQuadsForLayer(CCLayerImpl*);
+    void appendQuadsForLayer(CCLayerImpl*, CCOcclusionTrackerImpl*, CCOverdrawCounts*);
     void appendQuadsForRenderSurfaceLayer(CCLayerImpl*);
 
-    // Passing in 0 for CCOverdrawCounts is valid, and disables performing overdraw calculations.
-    void optimizeQuads(bool haveDamageRect, const FloatRect& damageRect, CCOverdrawCounts*);
-
     const CCQuadList& quadList() const { return m_quadList; }
     CCRenderSurface* targetSurface() const { return m_targetSurface; }
 
index 872a358..437f4f7 100644 (file)
@@ -34,6 +34,7 @@
 #include "ManagedTexture.h"
 #include "PlatformCanvas.h"
 #include "ScrollbarTheme.h"
+#include "cc/CCQuadCuller.h"
 
 namespace WebCore {
 
@@ -78,7 +79,7 @@ void CCScrollbarLayerImpl::willDraw(LayerRendererChromium* layerRenderer)
     }
 }
 
-void CCScrollbarLayerImpl::appendQuads(CCQuadList& quadList, const CCSharedQuadState* sharedQuadState)
+void CCScrollbarLayerImpl::appendQuads(CCQuadCuller& quadList, const CCSharedQuadState* sharedQuadState)
 {
     if (!m_texture->isReserved())
         return;
index f6f0053..fcec110 100644 (file)
@@ -60,7 +60,7 @@ public:
     void setScrollLayer(CCLayerImpl* scrollLayer) { m_scrollLayer = scrollLayer; }
 
     virtual void willDraw(LayerRendererChromium*);
-    virtual void appendQuads(CCQuadList&, const CCSharedQuadState*);
+    virtual void appendQuads(CCQuadCuller&, const CCSharedQuadState*);
     virtual void didDraw();
 
 protected:
index 864aff3..bf670ec 100644 (file)
@@ -30,6 +30,7 @@
 #include "cc/CCSolidColorLayerImpl.h"
 
 #include "LayerRendererChromium.h"
+#include "cc/CCQuadCuller.h"
 #include "cc/CCSolidColorDrawQuad.h"
 #include <wtf/MathExtras.h>
 #include <wtf/text/WTFString.h>
@@ -56,7 +57,7 @@ TransformationMatrix CCSolidColorLayerImpl::quadTransform() const
     return solidColorTransform;
 }
 
-void CCSolidColorLayerImpl::appendQuads(CCQuadList& quadList, const CCSharedQuadState* sharedQuadState)
+void CCSolidColorLayerImpl::appendQuads(CCQuadCuller& quadList, const CCSharedQuadState* sharedQuadState)
 {
     // We create a series of smaller quads instead of just one large one so that the
     // culler can reduce the total pixels drawn.
index 2e74416..7d07673 100644 (file)
@@ -42,7 +42,7 @@ public:
     virtual ~CCSolidColorLayerImpl();
 
     virtual TransformationMatrix quadTransform() const;
-    virtual void appendQuads(CCQuadList&, const CCSharedQuadState*);
+    virtual void appendQuads(CCQuadCuller&, const CCSharedQuadState*);
 
 protected:
     explicit CCSolidColorLayerImpl(int id);
index e8d2a6c..a1877b9 100644 (file)
@@ -31,6 +31,7 @@
 
 #include "LayerRendererChromium.h"
 #include "cc/CCDebugBorderDrawQuad.h"
+#include "cc/CCQuadCuller.h"
 #include "cc/CCSolidColorDrawQuad.h"
 #include "cc/CCTileDrawQuad.h"
 #include <wtf/text/WTFString.h>
@@ -122,7 +123,7 @@ TransformationMatrix CCTiledLayerImpl::quadTransform() const
     return transform;
 }
 
-void CCTiledLayerImpl::appendQuads(CCQuadList& quadList, const CCSharedQuadState* sharedQuadState)
+void CCTiledLayerImpl::appendQuads(CCQuadCuller& quadList, const CCSharedQuadState* sharedQuadState)
 {
     const IntRect& layerRect = visibleLayerRect();
 
index 84fe476..0be6577 100644 (file)
@@ -43,7 +43,7 @@ public:
     }
     virtual ~CCTiledLayerImpl();
 
-    virtual void appendQuads(CCQuadList&, const CCSharedQuadState*);
+    virtual void appendQuads(CCQuadCuller&, const CCSharedQuadState*);
 
     virtual void bindContentsTexture(LayerRendererChromium*);
 
index fd53e41..480c74e 100644 (file)
@@ -36,6 +36,7 @@
 #include "ProgramBinding.h"
 #include "cc/CCLayerTreeHostImpl.h"
 #include "cc/CCProxy.h"
+#include "cc/CCQuadCuller.h"
 #include "cc/CCVideoDrawQuad.h"
 #include <wtf/text/WTFString.h>
 
@@ -153,7 +154,7 @@ void CCVideoLayerImpl::willDraw(LayerRendererChromium* layerRenderer)
     }
 }
 
-void CCVideoLayerImpl::appendQuads(CCQuadList& quadList, const CCSharedQuadState* sharedQuadState)
+void CCVideoLayerImpl::appendQuads(CCQuadCuller& quadList, const CCSharedQuadState* sharedQuadState)
 {
     IntRect quadRect(IntPoint(), bounds());
     OwnPtr<CCVideoDrawQuad> videoQuad = CCVideoDrawQuad::create(sharedQuadState, quadRect, m_textures, m_frame, m_format);
index 4c4e231..4fb45eb 100644 (file)
@@ -50,7 +50,7 @@ public:
     virtual ~CCVideoLayerImpl();
 
     virtual void willDraw(LayerRendererChromium*);
-    virtual void appendQuads(CCQuadList&, const CCSharedQuadState*);
+    virtual void appendQuads(CCQuadCuller&, const CCSharedQuadState*);
     virtual void didDraw();
 
     typedef ProgramBinding<VertexShaderPosTexTransform, FragmentShaderRGBATexFlipAlpha> RGBAProgram;
index 6710bae..d4e3123 100644 (file)
@@ -1,3 +1,33 @@
+2012-03-13  Dana Jansens  <danakj@chromium.org>
+
+        [chromium] Use CCOcclusionTracker for draw culling
+        https://bugs.webkit.org/show_bug.cgi?id=80743
+
+        Reviewed by Adrienne Walker.
+
+        * WebKit.gypi:
+        * tests/CCLayerTreeHostImplTest.cpp:
+        (WebKit::BlendStateCheckLayer::appendQuads):
+        * tests/CCQuadCullerTest.cpp:
+        (TestCCOcclusionTrackerImpl):
+        (WebCore::TestCCOcclusionTrackerImpl::TestCCOcclusionTrackerImpl):
+        (WebCore::TestCCOcclusionTrackerImpl::layerScissorRectInTargetSurface):
+        (WebCore::makeLayer):
+        (WebCore::appendQuads):
+        (WebCore):
+        (WebCore::TEST):
+        * tests/CCSolidColorLayerImplTest.cpp:
+        (CCLayerTestCommon::TEST):
+        * tests/CCTiledLayerImplTest.cpp:
+        (CCLayerTestCommon::TEST):
+        (CCLayerTestCommon::getQuads):
+        * tests/MockCCQuadCuller.h: Added.
+        (WebCore):
+        (MockCCQuadCuller):
+        (WebCore::MockCCQuadCuller::MockCCQuadCuller):
+        (WebCore::MockCCQuadCuller::append):
+        (WebCore::MockCCQuadCuller::quadList):
+
 2012-03-13  Adam Barth  <abarth@webkit.org> && Benjamin Poulain  <bpoulain@apple.com>
 
         Always enable ENABLE(CLIENT_BASED_GEOLOCATION)
index 14760a4..d7bc6bc 100644 (file)
             'tests/LayerTextureUpdaterTest.cpp',
             'tests/LevelDBTest.cpp',
             'tests/LocalizedNumberICUTest.cpp',
+            'tests/MockCCQuadCuller.h',
             'tests/PaintAggregatorTest.cpp',
             'tests/PlatformGestureCurveTest.cpp',
             'tests/PlatformContextSkiaTest.cpp',
index d75c128..671ffed 100644 (file)
@@ -513,7 +513,7 @@ class BlendStateCheckLayer : public CCLayerImpl {
 public:
     static PassOwnPtr<BlendStateCheckLayer> create(int id) { return adoptPtr(new BlendStateCheckLayer(id)); }
 
-    virtual void appendQuads(CCQuadList& quadList, const CCSharedQuadState* sharedQuadState)
+    virtual void appendQuads(CCQuadCuller& quadList, const CCSharedQuadState* sharedQuadState)
     {
         m_quadsAppended = true;
 
index 42776bc..fa69441 100644 (file)
@@ -26,6 +26,9 @@
 
 #include "cc/CCQuadCuller.h"
 
+#include "cc/CCOcclusionTracker.h"
+#include "cc/CCSingleThreadProxy.h"
+#include "cc/CCTiledLayerImpl.h"
 #include "cc/CCTileDrawQuad.h"
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
@@ -34,53 +37,90 @@ using namespace WebCore;
 
 namespace {
 
-class CCQuadCullerTest : public testing::Test {
+class TestCCOcclusionTrackerImpl : public CCOcclusionTrackerImpl {
+public:
+    TestCCOcclusionTrackerImpl(const IntRect& scissorRectInScreen)
+        : CCOcclusionTrackerImpl(scissorRectInScreen)
+        , m_scissorRectInScreen(scissorRectInScreen)
+    {
+        // Pretend we have visited a render surface.
+        m_stack.append(StackObject());
+    }
+
+protected:
+    virtual IntRect layerScissorRectInTargetSurface(const CCLayerImpl* layer) const { return m_scissorRectInScreen; }
+
+private:
+    IntRect m_scissorRectInScreen;
 };
 
-static PassOwnPtr<CCDrawQuad> MakeTileQuad(CCSharedQuadState* state, const IntRect& rect, const IntRect& opaqueRect = IntRect())
+static PassOwnPtr<CCTiledLayerImpl> makeLayer(const TransformationMatrix& drawTransform, const IntRect& layerRect, float opacity, bool opaque, const IntRect& layerOpaqueRect)
 {
-    return CCTileDrawQuad::create(state, rect, intersection(rect, opaqueRect), 1, IntPoint(1, 1), IntSize(100, 100), 0, false, false, false, false, false);
+    OwnPtr<CCTiledLayerImpl> layer = CCTiledLayerImpl::create(0);
+    OwnPtr<CCLayerTilingData> tiler = CCLayerTilingData::create(IntSize(100, 100), CCLayerTilingData::NoBorderTexels);
+    tiler->setBounds(layerRect.size());
+    layer->setTilingData(*tiler);
+    layer->setSkipsDraw(false);
+    layer->setDrawTransform(drawTransform);
+    layer->setScreenSpaceTransform(drawTransform);
+    layer->setVisibleLayerRect(layerRect);
+    layer->setDrawOpacity(opacity);
+    layer->setOpaque(opaque);
+
+    int textureId = 1;
+    for (int i = 0; i < tiler->numTilesX(); ++i)
+        for (int j = 0; j < tiler->numTilesY(); ++j) {
+            IntRect tileOpaqueRect = opaque ? tiler->tileBounds(i, j) : intersection(tiler->tileBounds(i, j), layerOpaqueRect);
+            layer->pushTileProperties(i, j, static_cast<Platform3DObject>(textureId++), tileOpaqueRect);
+        }
+
+    return layer.release();
 }
 
-void setQuads(CCSharedQuadState* rootState, CCSharedQuadState* childState, CCQuadList& quadList, const IntRect& opaqueRect = IntRect())
+static void appendQuads(CCQuadList& quadList, CCTiledLayerImpl* layer, CCOcclusionTrackerImpl& occlusionTracker, CCOverdrawCounts& overdraw)
 {
-    quadList.clear();
-
-    quadList.append(MakeTileQuad(rootState, IntRect(IntPoint(), IntSize(100, 100)), opaqueRect));
-    quadList.append(MakeTileQuad(rootState, IntRect(IntPoint(100, 0), IntSize(100, 100)), opaqueRect));
-    quadList.append(MakeTileQuad(rootState, IntRect(IntPoint(200, 0), IntSize(100, 100)), opaqueRect));
-    quadList.append(MakeTileQuad(rootState, IntRect(IntPoint(0, 100), IntSize(100, 100)), opaqueRect));
-    quadList.append(MakeTileQuad(rootState, IntRect(IntPoint(100, 100), IntSize(100, 100)), opaqueRect));
-    quadList.append(MakeTileQuad(rootState, IntRect(IntPoint(200, 100), IntSize(100, 100)), opaqueRect));
-    quadList.append(MakeTileQuad(rootState, IntRect(IntPoint(0, 200), IntSize(100, 100)), opaqueRect));
-    quadList.append(MakeTileQuad(rootState, IntRect(IntPoint(100, 200), IntSize(100, 100)), opaqueRect));
-    quadList.append(MakeTileQuad(rootState, IntRect(IntPoint(200, 200), IntSize(100, 100)), opaqueRect));
-
-    quadList.append(MakeTileQuad(childState, IntRect(IntPoint(), IntSize(100, 100)), opaqueRect));
-    quadList.append(MakeTileQuad(childState, IntRect(IntPoint(100, 0), IntSize(100, 100)), opaqueRect));
-    quadList.append(MakeTileQuad(childState, IntRect(IntPoint(0, 100), IntSize(100, 100)), opaqueRect));
-    quadList.append(MakeTileQuad(childState, IntRect(IntPoint(100, 100), IntSize(100, 100)), opaqueRect));
+    CCQuadCuller quadCuller(quadList, layer, &occlusionTracker, &overdraw);
+    OwnPtr<CCSharedQuadState> sharedQuadState = layer->createSharedQuadState();
+    layer->appendQuads(quadCuller, sharedQuadState.get());
 }
 
 #define DECLARE_AND_INITIALIZE_TEST_QUADS               \
+    DebugScopedSetImplThread impl;                      \
     CCQuadList quadList;                                \
-    CCOverdrawCounts overdraw;              \
+    CCOverdrawCounts overdraw;                          \
     TransformationMatrix childTransform;                \
     IntSize rootSize = IntSize(300, 300);               \
     IntRect rootRect = IntRect(IntPoint(), rootSize);   \
     IntSize childSize = IntSize(200, 200);              \
     IntRect childRect = IntRect(IntPoint(), childSize);
 
-TEST(CCQuadCullerTest, verifyCullChildLinesUpTopLeft)
+TEST(CCQuadCullerTest, verifyNoCulling)
 {
     DECLARE_AND_INITIALIZE_TEST_QUADS
 
-    OwnPtr<CCSharedQuadState> rootState = CCSharedQuadState::create(TransformationMatrix(), TransformationMatrix(), rootRect, IntRect(), 1.0, true);
-    OwnPtr<CCSharedQuadState> childState = CCSharedQuadState::create(childTransform, TransformationMatrix(), childRect, IntRect(), 1.0, true);
+    OwnPtr<CCTiledLayerImpl> rootLayer = makeLayer(TransformationMatrix(), rootRect, 1.0, true, IntRect());
+    OwnPtr<CCTiledLayerImpl> childLayer = makeLayer(TransformationMatrix(), childRect, 1.0, true, IntRect());
+    TestCCOcclusionTrackerImpl occlusionTracker(IntRect(-100, -100, 1000, 1000));
 
-    setQuads(rootState.get(), childState.get(), quadList);
+    appendQuads(quadList, childLayer.get(), occlusionTracker, overdraw);
+    appendQuads(quadList, rootLayer.get(), occlusionTracker, overdraw);
     EXPECT_EQ(quadList.size(), 13u);
-    CCQuadCuller::cullOccludedQuads(quadList, false, IntRect(), &overdraw);
+    EXPECT_NEAR(overdraw.m_pixelsDrawnOpaque, 130000, 1);
+    EXPECT_NEAR(overdraw.m_pixelsDrawnTransparent, 0, 1);
+    EXPECT_NEAR(overdraw.m_pixelsCulled, 0, 1);
+}
+
+TEST(CCQuadCullerTest, verifyCullChildLinesUpTopLeft)
+{
+    DECLARE_AND_INITIALIZE_TEST_QUADS
+
+    OwnPtr<CCTiledLayerImpl> rootLayer = makeLayer(TransformationMatrix(), rootRect, 1.0, true, IntRect());
+    OwnPtr<CCTiledLayerImpl> childLayer = makeLayer(TransformationMatrix(), childRect, 1.0, true, IntRect());
+    TestCCOcclusionTrackerImpl occlusionTracker(IntRect(-100, -100, 1000, 1000));
+
+    appendQuads(quadList, childLayer.get(), occlusionTracker, overdraw);
+    occlusionTracker.markOccludedBehindLayer(childLayer.get());
+    appendQuads(quadList, rootLayer.get(), occlusionTracker, overdraw);
     EXPECT_EQ(quadList.size(), 9u);
     EXPECT_NEAR(overdraw.m_pixelsDrawnOpaque, 90000, 1);
     EXPECT_NEAR(overdraw.m_pixelsDrawnTransparent, 0, 1);
@@ -91,12 +131,13 @@ TEST(CCQuadCullerTest, verifyCullWhenChildOpacityNotOne)
 {
     DECLARE_AND_INITIALIZE_TEST_QUADS
 
-    OwnPtr<CCSharedQuadState> rootState = CCSharedQuadState::create(TransformationMatrix(), TransformationMatrix(), rootRect, IntRect(), 1.0, true);
-    OwnPtr<CCSharedQuadState> childState = CCSharedQuadState::create(childTransform, TransformationMatrix(), childRect, IntRect(), 0.9, true);
+    OwnPtr<CCTiledLayerImpl> rootLayer = makeLayer(TransformationMatrix(), rootRect, 1.0, true, IntRect());
+    OwnPtr<CCTiledLayerImpl> childLayer = makeLayer(childTransform, childRect, 0.9, true, IntRect());
+    TestCCOcclusionTrackerImpl occlusionTracker(IntRect(-100, -100, 1000, 1000));
 
-    setQuads(rootState.get(), childState.get(), quadList);
-    EXPECT_EQ(quadList.size(), 13u);
-    CCQuadCuller::cullOccludedQuads(quadList, false, IntRect(), &overdraw);
+    appendQuads(quadList, childLayer.get(), occlusionTracker, overdraw);
+    occlusionTracker.markOccludedBehindLayer(childLayer.get());
+    appendQuads(quadList, rootLayer.get(), occlusionTracker, overdraw);
     EXPECT_EQ(quadList.size(), 13u);
     EXPECT_NEAR(overdraw.m_pixelsDrawnOpaque, 90000, 1);
     EXPECT_NEAR(overdraw.m_pixelsDrawnTransparent, 40000, 1);
@@ -107,12 +148,13 @@ TEST(CCQuadCullerTest, verifyCullWhenChildOpaqueFlagFalse)
 {
     DECLARE_AND_INITIALIZE_TEST_QUADS
 
-    OwnPtr<CCSharedQuadState> rootState = CCSharedQuadState::create(TransformationMatrix(), TransformationMatrix(), rootRect, IntRect(), 1.0, true);
-    OwnPtr<CCSharedQuadState> childState = CCSharedQuadState::create(childTransform, TransformationMatrix(), childRect, IntRect(), 1.0, false);
+    OwnPtr<CCTiledLayerImpl> rootLayer = makeLayer(TransformationMatrix(), rootRect, 1.0, true, IntRect());
+    OwnPtr<CCTiledLayerImpl> childLayer = makeLayer(childTransform, childRect, 1.0, false, IntRect());
+    TestCCOcclusionTrackerImpl occlusionTracker(IntRect(-100, -100, 1000, 1000));
 
-    setQuads(rootState.get(), childState.get(), quadList);
-    EXPECT_EQ(quadList.size(), 13u);
-    CCQuadCuller::cullOccludedQuads(quadList, false, IntRect(), &overdraw);
+    appendQuads(quadList, childLayer.get(), occlusionTracker, overdraw);
+    occlusionTracker.markOccludedBehindLayer(childLayer.get());
+    appendQuads(quadList, rootLayer.get(), occlusionTracker, overdraw);
     EXPECT_EQ(quadList.size(), 13u);
     EXPECT_NEAR(overdraw.m_pixelsDrawnOpaque, 90000, 1);
     EXPECT_NEAR(overdraw.m_pixelsDrawnTransparent, 40000, 1);
@@ -125,26 +167,27 @@ TEST(CCQuadCullerTest, verifyCullCenterTileOnly)
 
     childTransform.translate(50, 50);
 
-    OwnPtr<CCSharedQuadState> rootState = CCSharedQuadState::create(TransformationMatrix(), TransformationMatrix(), rootRect, IntRect(), 1.0, true);
-    OwnPtr<CCSharedQuadState> childState = CCSharedQuadState::create(childTransform, TransformationMatrix(), childRect, IntRect(), 1.0, true);
+    OwnPtr<CCTiledLayerImpl> rootLayer = makeLayer(TransformationMatrix(), rootRect, 1.0, true, IntRect());
+    OwnPtr<CCTiledLayerImpl> childLayer = makeLayer(childTransform, childRect, 1.0, true, IntRect());
+    TestCCOcclusionTrackerImpl occlusionTracker(IntRect(-100, -100, 1000, 1000));
 
-    setQuads(rootState.get(), childState.get(), quadList);
-    EXPECT_EQ(quadList.size(), 13u);
-    CCQuadCuller::cullOccludedQuads(quadList, false, IntRect(), &overdraw);
+    appendQuads(quadList, childLayer.get(), occlusionTracker, overdraw);
+    occlusionTracker.markOccludedBehindLayer(childLayer.get());
+    appendQuads(quadList, rootLayer.get(), occlusionTracker, overdraw);
     EXPECT_EQ(quadList.size(), 12u);
 
-    IntRect quadVisibleRect1 = quadList[1].get()->quadVisibleRect();
+    IntRect quadVisibleRect1 = quadList[5].get()->quadVisibleRect();
     EXPECT_EQ(quadVisibleRect1.height(), 50);
 
-    IntRect quadVisibleRect3 = quadList[3].get()->quadVisibleRect();
+    IntRect quadVisibleRect3 = quadList[7].get()->quadVisibleRect();
     EXPECT_EQ(quadVisibleRect3.width(), 50);
 
-    // Next index is 4, not 5, since centre quad culled.
-    IntRect quadVisibleRect4 = quadList[4].get()->quadVisibleRect();
+    // Next index is 8, not 9, since centre quad culled.
+    IntRect quadVisibleRect4 = quadList[8].get()->quadVisibleRect();
     EXPECT_EQ(quadVisibleRect4.width(), 50);
     EXPECT_EQ(quadVisibleRect4.x(), 250);
 
-    IntRect quadVisibleRect6 = quadList[6].get()->quadVisibleRect();
+    IntRect quadVisibleRect6 = quadList[10].get()->quadVisibleRect();
     EXPECT_EQ(quadVisibleRect6.height(), 50);
     EXPECT_EQ(quadVisibleRect6.y(), 250);
 
@@ -159,20 +202,21 @@ TEST(CCQuadCullerTest, verifyCullCenterTileNonIntegralSize1)
 
     childTransform.translate(100, 100);
 
-    // Create root layer tile with extent (99.1, 99.1) -> (200.9, 200.9) to make
+    // Make the root layer's quad have extent (99.1, 99.1) -> (200.9, 200.9) to make
     // sure it doesn't get culled due to transform rounding.
     TransformationMatrix rootTransform;
     rootTransform.translate(99.1, 99.1);
     rootTransform.scale(1.018);
 
-    OwnPtr<CCSharedQuadState> rootState = CCSharedQuadState::create(rootTransform, TransformationMatrix(), rootRect, IntRect(), 1.0, true);
-    OwnPtr<CCSharedQuadState> childState = CCSharedQuadState::create(childTransform, TransformationMatrix(), childRect, IntRect(), 1.0, true);
+    rootRect = childRect = IntRect(0, 0, 100, 100);
 
-    quadList.append(MakeTileQuad(rootState.get(), IntRect(IntPoint(), IntSize(100, 100))));
-    quadList.append(MakeTileQuad(childState.get(), IntRect(IntPoint(), IntSize(100, 100))));
+    OwnPtr<CCTiledLayerImpl> rootLayer = makeLayer(rootTransform, rootRect, 1.0, true, IntRect());
+    OwnPtr<CCTiledLayerImpl> childLayer = makeLayer(childTransform, childRect, 1.0, true, IntRect());
+    TestCCOcclusionTrackerImpl occlusionTracker(IntRect(-100, -100, 1000, 1000));
 
-    EXPECT_EQ(quadList.size(), 2u);
-    CCQuadCuller::cullOccludedQuads(quadList, false, IntRect(), &overdraw);
+    appendQuads(quadList, childLayer.get(), occlusionTracker, overdraw);
+    occlusionTracker.markOccludedBehindLayer(childLayer.get());
+    appendQuads(quadList, rootLayer.get(), occlusionTracker, overdraw);
     EXPECT_EQ(quadList.size(), 2u);
 
     EXPECT_NEAR(overdraw.m_pixelsDrawnOpaque, 20363, 1);
@@ -184,7 +228,7 @@ TEST(CCQuadCullerTest, verifyCullCenterTileNonIntegralSize2)
 {
     DECLARE_AND_INITIALIZE_TEST_QUADS
 
-    // Make the child quad slightly smaller than, and centred over, the root layer tile.
+    // Make the child's quad slightly smaller than, and centred over, the root layer tile.
     // Verify the child does not cause the quad below to be culled due to rounding.
     childTransform.translate(100.1, 100.1);
     childTransform.scale(0.982);
@@ -192,14 +236,15 @@ TEST(CCQuadCullerTest, verifyCullCenterTileNonIntegralSize2)
     TransformationMatrix rootTransform;
     rootTransform.translate(100, 100);
 
-    OwnPtr<CCSharedQuadState> rootState = CCSharedQuadState::create(rootTransform, TransformationMatrix(), rootRect, IntRect(), 1.0, true);
-    OwnPtr<CCSharedQuadState> childState = CCSharedQuadState::create(childTransform, TransformationMatrix(), childRect, IntRect(), 1.0, true);
+    rootRect = childRect = IntRect(0, 0, 100, 100);
 
-    quadList.append(MakeTileQuad(rootState.get(), IntRect(IntPoint(), IntSize(100, 100))));
-    quadList.append(MakeTileQuad(childState.get(), IntRect(IntPoint(), IntSize(100, 100))));
+    OwnPtr<CCTiledLayerImpl> rootLayer = makeLayer(rootTransform, rootRect, 1.0, true, IntRect());
+    OwnPtr<CCTiledLayerImpl> childLayer = makeLayer(childTransform, childRect, 1.0, true, IntRect());
+    TestCCOcclusionTrackerImpl occlusionTracker(IntRect(-100, -100, 1000, 1000));
 
-    EXPECT_EQ(quadList.size(), 2u);
-    CCQuadCuller::cullOccludedQuads(quadList, false, IntRect(), &overdraw);
+    appendQuads(quadList, childLayer.get(), occlusionTracker, overdraw);
+    occlusionTracker.markOccludedBehindLayer(childLayer.get());
+    appendQuads(quadList, rootLayer.get(), occlusionTracker, overdraw);
     EXPECT_EQ(quadList.size(), 2u);
 
     EXPECT_NEAR(overdraw.m_pixelsDrawnOpaque, 19643, 1);
@@ -213,12 +258,13 @@ TEST(CCQuadCullerTest, verifyCullChildLinesUpBottomRight)
 
     childTransform.translate(100, 100);
 
-    OwnPtr<CCSharedQuadState> rootState = CCSharedQuadState::create(TransformationMatrix(), TransformationMatrix(), rootRect, IntRect(), 1.0, true);
-    OwnPtr<CCSharedQuadState> childState = CCSharedQuadState::create(childTransform, TransformationMatrix(), childRect, IntRect(), 1.0, true);
+    OwnPtr<CCTiledLayerImpl> rootLayer = makeLayer(TransformationMatrix(), rootRect, 1.0, true, IntRect());
+    OwnPtr<CCTiledLayerImpl> childLayer = makeLayer(childTransform, childRect, 1.0, true, IntRect());
+    TestCCOcclusionTrackerImpl occlusionTracker(IntRect(-100, -100, 1000, 1000));
 
-    setQuads(rootState.get(), childState.get(), quadList);
-    EXPECT_EQ(quadList.size(), 13u);
-    CCQuadCuller::cullOccludedQuads(quadList, false, IntRect(), &overdraw);
+    appendQuads(quadList, childLayer.get(), occlusionTracker, overdraw);
+    occlusionTracker.markOccludedBehindLayer(childLayer.get());
+    appendQuads(quadList, rootLayer.get(), occlusionTracker, overdraw);
     EXPECT_EQ(quadList.size(), 9u);
     EXPECT_NEAR(overdraw.m_pixelsDrawnOpaque, 90000, 1);
     EXPECT_NEAR(overdraw.m_pixelsDrawnTransparent, 0, 1);
@@ -231,13 +277,14 @@ TEST(CCQuadCullerTest, verifyCullSubRegion)
 
     childTransform.translate(50, 50);
 
-    OwnPtr<CCSharedQuadState> rootState = CCSharedQuadState::create(TransformationMatrix(), TransformationMatrix(), rootRect, IntRect(), 1.0, true);
-    OwnPtr<CCSharedQuadState> childState = CCSharedQuadState::create(childTransform, TransformationMatrix(), childRect, IntRect(), 1.0, false);
+    OwnPtr<CCTiledLayerImpl> rootLayer = makeLayer(TransformationMatrix(), rootRect, 1.0, true, IntRect());
     IntRect childOpaqueRect(childRect.x() + childRect.width() / 4, childRect.y() + childRect.height() / 4, childRect.width() / 2, childRect.height() / 2);
+    OwnPtr<CCTiledLayerImpl> childLayer = makeLayer(childTransform, childRect, 1.0, false, childOpaqueRect);
+    TestCCOcclusionTrackerImpl occlusionTracker(IntRect(-100, -100, 1000, 1000));
 
-    setQuads(rootState.get(), childState.get(), quadList, childOpaqueRect);
-    EXPECT_EQ(quadList.size(), 13u);
-    CCQuadCuller::cullOccludedQuads(quadList, false, IntRect(), &overdraw);
+    appendQuads(quadList, childLayer.get(), occlusionTracker, overdraw);
+    occlusionTracker.markOccludedBehindLayer(childLayer.get());
+    appendQuads(quadList, rootLayer.get(), occlusionTracker, overdraw);
     EXPECT_EQ(quadList.size(), 12u);
     EXPECT_NEAR(overdraw.m_pixelsDrawnOpaque, 90000, 1);
     EXPECT_NEAR(overdraw.m_pixelsDrawnTransparent, 30000, 1);
@@ -250,13 +297,14 @@ TEST(CCQuadCullerTest, verifyCullSubRegion2)
 
     childTransform.translate(50, 10);
 
-    OwnPtr<CCSharedQuadState> rootState = CCSharedQuadState::create(TransformationMatrix(), TransformationMatrix(), rootRect, IntRect(), 1.0, true);
-    OwnPtr<CCSharedQuadState> childState = CCSharedQuadState::create(childTransform, TransformationMatrix(), childRect, IntRect(), 1.0, false);
+    OwnPtr<CCTiledLayerImpl> rootLayer = makeLayer(TransformationMatrix(), rootRect, 1.0, true, IntRect());
     IntRect childOpaqueRect(childRect.x() + childRect.width() / 4, childRect.y() + childRect.height() / 4, childRect.width() / 2, childRect.height() * 3 / 4);
+    OwnPtr<CCTiledLayerImpl> childLayer = makeLayer(childTransform, childRect, 1.0, false, childOpaqueRect);
+    TestCCOcclusionTrackerImpl occlusionTracker(IntRect(-100, -100, 1000, 1000));
 
-    setQuads(rootState.get(), childState.get(), quadList, childOpaqueRect);
-    EXPECT_EQ(quadList.size(), 13u);
-    CCQuadCuller::cullOccludedQuads(quadList, false, IntRect(), &overdraw);
+    appendQuads(quadList, childLayer.get(), occlusionTracker, overdraw);
+    occlusionTracker.markOccludedBehindLayer(childLayer.get());
+    appendQuads(quadList, rootLayer.get(), occlusionTracker, overdraw);
     EXPECT_EQ(quadList.size(), 12u);
     EXPECT_NEAR(overdraw.m_pixelsDrawnOpaque, 90000, 1);
     EXPECT_NEAR(overdraw.m_pixelsDrawnTransparent, 25000, 1);
@@ -269,14 +317,18 @@ TEST(CCQuadCullerTest, verifyCullSubRegionCheckOvercull)
 
     childTransform.translate(50, 49);
 
-    OwnPtr<CCSharedQuadState> rootState = CCSharedQuadState::create(TransformationMatrix(), TransformationMatrix(), rootRect, IntRect(), 1.0, true);
-    OwnPtr<CCSharedQuadState> childState = CCSharedQuadState::create(childTransform, TransformationMatrix(), childRect, IntRect(), 1.0, false);
+    OwnPtr<CCTiledLayerImpl> rootLayer = makeLayer(TransformationMatrix(), rootRect, 1.0, true, IntRect());
     IntRect childOpaqueRect(childRect.x() + childRect.width() / 4, childRect.y() + childRect.height() / 4, childRect.width() / 2, childRect.height() / 2);
+    OwnPtr<CCTiledLayerImpl> childLayer = makeLayer(childTransform, childRect, 1.0, false, childOpaqueRect);
+    TestCCOcclusionTrackerImpl occlusionTracker(IntRect(-100, -100, 1000, 1000));
 
-    setQuads(rootState.get(), childState.get(), quadList, childOpaqueRect);
-    EXPECT_EQ(quadList.size(), 13u);
-    CCQuadCuller::cullOccludedQuads(quadList, false, IntRect(), &overdraw);
+    appendQuads(quadList, childLayer.get(), occlusionTracker, overdraw);
+    occlusionTracker.markOccludedBehindLayer(childLayer.get());
+    appendQuads(quadList, rootLayer.get(), occlusionTracker, overdraw);
     EXPECT_EQ(quadList.size(), 13u);
+    EXPECT_NEAR(overdraw.m_pixelsDrawnOpaque, 90000, 1);
+    EXPECT_NEAR(overdraw.m_pixelsDrawnTransparent, 30000, 1);
+    EXPECT_NEAR(overdraw.m_pixelsCulled, 10000, 1);
 }
 
 TEST(CCQuadCullerTest, verifyNonAxisAlignedQuadsDontOcclude)
@@ -286,12 +338,13 @@ TEST(CCQuadCullerTest, verifyNonAxisAlignedQuadsDontOcclude)
     // Use a small rotation so as to not disturb the geometry significantly.
     childTransform.rotate(1);
 
-    OwnPtr<CCSharedQuadState> rootState = CCSharedQuadState::create(TransformationMatrix(), TransformationMatrix(), rootRect, IntRect(), 1.0, true);
-    OwnPtr<CCSharedQuadState> childState = CCSharedQuadState::create(childTransform, TransformationMatrix(), childRect, IntRect(), 1.0, true);
+    OwnPtr<CCTiledLayerImpl> rootLayer = makeLayer(TransformationMatrix(), rootRect, 1.0, true, IntRect());
+    OwnPtr<CCTiledLayerImpl> childLayer = makeLayer(childTransform, childRect, 1.0, true, IntRect());
+    TestCCOcclusionTrackerImpl occlusionTracker(IntRect(-100, -100, 1000, 1000));
 
-    setQuads(rootState.get(), childState.get(), quadList);
-    EXPECT_EQ(quadList.size(), 13u);
-    CCQuadCuller::cullOccludedQuads(quadList, false, IntRect(), &overdraw);
+    appendQuads(quadList, childLayer.get(), occlusionTracker, overdraw);
+    occlusionTracker.markOccludedBehindLayer(childLayer.get());
+    appendQuads(quadList, rootLayer.get(), occlusionTracker, overdraw);
     EXPECT_EQ(quadList.size(), 13u);
     EXPECT_NEAR(overdraw.m_pixelsDrawnOpaque, 130000, 1);
     EXPECT_NEAR(overdraw.m_pixelsDrawnTransparent, 0, 1);
@@ -311,28 +364,30 @@ TEST(CCQuadCullerTest, verifyNonAxisAlignedQuadsSafelyCulled)
     TransformationMatrix parentTransform;
     parentTransform.rotate(1);
 
-    OwnPtr<CCSharedQuadState> rootState = CCSharedQuadState::create(parentTransform, TransformationMatrix(), rootRect, IntRect(), 1.0, true);
-    OwnPtr<CCSharedQuadState> childState = CCSharedQuadState::create(TransformationMatrix(), TransformationMatrix(), childRect, IntRect(), 1.0, true);
+    OwnPtr<CCTiledLayerImpl> rootLayer = makeLayer(parentTransform, rootRect, 1.0, true, IntRect());
+    OwnPtr<CCTiledLayerImpl> childLayer = makeLayer(TransformationMatrix(), childRect, 1.0, true, IntRect());
+    TestCCOcclusionTrackerImpl occlusionTracker(IntRect(-100, -100, 1000, 1000));
 
-    setQuads(rootState.get(), childState.get(), quadList);
-    EXPECT_EQ(quadList.size(), 13u);
-    CCQuadCuller::cullOccludedQuads(quadList, false, IntRect(), &overdraw);
+    appendQuads(quadList, childLayer.get(), occlusionTracker, overdraw);
+    occlusionTracker.markOccludedBehindLayer(childLayer.get());
+    appendQuads(quadList, rootLayer.get(), occlusionTracker, overdraw);
     EXPECT_EQ(quadList.size(), 12u);
-    EXPECT_NEAR(overdraw.m_pixelsDrawnOpaque, 120000, 1);
+    EXPECT_NEAR(overdraw.m_pixelsDrawnOpaque, 100600, 1);
     EXPECT_NEAR(overdraw.m_pixelsDrawnTransparent, 0, 1);
-    EXPECT_NEAR(overdraw.m_pixelsCulled, 10000, 1);
+    EXPECT_NEAR(overdraw.m_pixelsCulled, 29400, 1);
 }
 
 TEST(CCQuadCullerTest, verifyCullOutsideScissorOverTile)
 {
     DECLARE_AND_INITIALIZE_TEST_QUADS
 
-    OwnPtr<CCSharedQuadState> rootState = CCSharedQuadState::create(TransformationMatrix(), TransformationMatrix(), rootRect, IntRect(), 1.0, true);
-    OwnPtr<CCSharedQuadState> childState = CCSharedQuadState::create(childTransform, TransformationMatrix(), childRect, IntRect(), 1.0, true);
+    OwnPtr<CCTiledLayerImpl> rootLayer = makeLayer(TransformationMatrix(), rootRect, 1.0, true, IntRect());
+    OwnPtr<CCTiledLayerImpl> childLayer = makeLayer(TransformationMatrix(), childRect, 1.0, true, IntRect());
+    TestCCOcclusionTrackerImpl occlusionTracker(IntRect(200, 100, 100, 100));
 
-    setQuads(rootState.get(), childState.get(), quadList);
-    EXPECT_EQ(quadList.size(), 13u);
-    CCQuadCuller::cullOccludedQuads(quadList, true, IntRect(200, 100, 100, 100), &overdraw);
+    appendQuads(quadList, childLayer.get(), occlusionTracker, overdraw);
+    occlusionTracker.markOccludedBehindLayer(childLayer.get());
+    appendQuads(quadList, rootLayer.get(), occlusionTracker, overdraw);
     EXPECT_EQ(quadList.size(), 1u);
     EXPECT_NEAR(overdraw.m_pixelsDrawnOpaque, 10000, 1);
     EXPECT_NEAR(overdraw.m_pixelsDrawnTransparent, 0, 1);
@@ -343,43 +398,51 @@ TEST(CCQuadCullerTest, verifyCullOutsideScissorOverCulledTile)
 {
     DECLARE_AND_INITIALIZE_TEST_QUADS
 
-    OwnPtr<CCSharedQuadState> rootState = CCSharedQuadState::create(TransformationMatrix(), TransformationMatrix(), rootRect, IntRect(), 1.0, true);
-    OwnPtr<CCSharedQuadState> childState = CCSharedQuadState::create(childTransform, TransformationMatrix(), childRect, IntRect(), 1.0, true);
+    OwnPtr<CCTiledLayerImpl> rootLayer = makeLayer(TransformationMatrix(), rootRect, 1.0, true, IntRect());
+    OwnPtr<CCTiledLayerImpl> childLayer = makeLayer(TransformationMatrix(), childRect, 1.0, true, IntRect());
+    TestCCOcclusionTrackerImpl occlusionTracker(IntRect(100, 100, 100, 100));
 
-    setQuads(rootState.get(), childState.get(), quadList);
-    EXPECT_EQ(quadList.size(), 13u);
-    CCQuadCuller::cullOccludedQuads(quadList, true, IntRect(100, 100, 100, 100), &overdraw);
+    appendQuads(quadList, childLayer.get(), occlusionTracker, overdraw);
+    occlusionTracker.markOccludedBehindLayer(childLayer.get());
+    appendQuads(quadList, rootLayer.get(), occlusionTracker, overdraw);
     EXPECT_EQ(quadList.size(), 1u);
+    EXPECT_NEAR(overdraw.m_pixelsDrawnOpaque, 10000, 1);
+    EXPECT_NEAR(overdraw.m_pixelsDrawnTransparent, 0, 1);
+    EXPECT_NEAR(overdraw.m_pixelsCulled, 120000, 1);
 }
 
 TEST(CCQuadCullerTest, verifyCullOutsideScissorOverPartialTiles)
 {
     DECLARE_AND_INITIALIZE_TEST_QUADS
 
-    OwnPtr<CCSharedQuadState> rootState = CCSharedQuadState::create(TransformationMatrix(), TransformationMatrix(), rootRect, IntRect(), 1.0, true);
-    OwnPtr<CCSharedQuadState> childState = CCSharedQuadState::create(childTransform, TransformationMatrix(), childRect, IntRect(), 1.0, true);
+    OwnPtr<CCTiledLayerImpl> rootLayer = makeLayer(TransformationMatrix(), rootRect, 1.0, true, IntRect());
+    OwnPtr<CCTiledLayerImpl> childLayer = makeLayer(TransformationMatrix(), childRect, 1.0, true, IntRect());
+    TestCCOcclusionTrackerImpl occlusionTracker(IntRect(50, 50, 200, 200));
 
-    setQuads(rootState.get(), childState.get(), quadList);
-    EXPECT_EQ(quadList.size(), 13u);
-    CCQuadCuller::cullOccludedQuads(quadList, true, IntRect(50, 50, 200, 200), &overdraw);
+    appendQuads(quadList, childLayer.get(), occlusionTracker, overdraw);
+    occlusionTracker.markOccludedBehindLayer(childLayer.get());
+    appendQuads(quadList, rootLayer.get(), occlusionTracker, overdraw);
     EXPECT_EQ(quadList.size(), 9u);
+    EXPECT_NEAR(overdraw.m_pixelsDrawnOpaque, 40000, 1);
+    EXPECT_NEAR(overdraw.m_pixelsDrawnTransparent, 0, 1);
+    EXPECT_NEAR(overdraw.m_pixelsCulled, 90000, 1);
 }
 
 TEST(CCQuadCullerTest, verifyCullOutsideScissorOverNoTiles)
 {
     DECLARE_AND_INITIALIZE_TEST_QUADS
 
-    OwnPtr<CCSharedQuadState> rootState = CCSharedQuadState::create(TransformationMatrix(), TransformationMatrix(), rootRect, IntRect(), 1.0, true);
-    OwnPtr<CCSharedQuadState> childState = CCSharedQuadState::create(childTransform, TransformationMatrix(), childRect, IntRect(), 1.0, true);
+    OwnPtr<CCTiledLayerImpl> rootLayer = makeLayer(TransformationMatrix(), rootRect, 1.0, true, IntRect());
+    OwnPtr<CCTiledLayerImpl> childLayer = makeLayer(TransformationMatrix(), childRect, 1.0, true, IntRect());
+    TestCCOcclusionTrackerImpl occlusionTracker(IntRect(500, 500, 100, 100));
 
-    setQuads(rootState.get(), childState.get(), quadList);
-    EXPECT_EQ(quadList.size(), 13u);
-    CCQuadCuller::cullOccludedQuads(quadList, true, IntRect(500, 500, 100, 100), &overdraw);
+    appendQuads(quadList, childLayer.get(), occlusionTracker, overdraw);
+    occlusionTracker.markOccludedBehindLayer(childLayer.get());
+    appendQuads(quadList, rootLayer.get(), occlusionTracker, overdraw);
     EXPECT_EQ(quadList.size(), 0u);
     EXPECT_NEAR(overdraw.m_pixelsDrawnOpaque, 0, 1);
     EXPECT_NEAR(overdraw.m_pixelsDrawnTransparent, 0, 1);
     EXPECT_NEAR(overdraw.m_pixelsCulled, 130000, 1);
 }
 
-
 } // namespace
index 02dc908..7c743d2 100644 (file)
@@ -27,6 +27,7 @@
 #include "cc/CCSolidColorLayerImpl.h"
 
 #include "CCLayerTestCommon.h"
+#include "MockCCQuadCuller.h"
 #include "cc/CCSingleThreadProxy.h"
 #include "cc/CCSolidColorDrawQuad.h"
 
@@ -42,7 +43,7 @@ TEST(CCSolidColorLayerImplTest, verifyTilingCompleteAndNoOverlap)
 {
     DebugScopedSetImplThread scopedImplThread;
 
-    CCQuadList quadList;
+    MockCCQuadCuller quadCuller;
     IntSize layerSize = IntSize(800, 600);
     IntRect visibleLayerRect = IntRect(IntPoint(), layerSize);
 
@@ -51,9 +52,9 @@ TEST(CCSolidColorLayerImplTest, verifyTilingCompleteAndNoOverlap)
     layer->setBounds(layerSize);
 
     OwnPtr<CCSharedQuadState> sharedQuadState = layer->createSharedQuadState();
-    layer->appendQuads(quadList, sharedQuadState.get());
+    layer->appendQuads(quadCuller, sharedQuadState.get());
 
-    verifyQuadsExactlyCoverRect(quadList, visibleLayerRect);
+    verifyQuadsExactlyCoverRect(quadCuller.quadList(), visibleLayerRect);
 }
 
 TEST(CCSolidColorLayerImplTest, verifyCorrectBackgroundColorInQuad)
@@ -62,7 +63,7 @@ TEST(CCSolidColorLayerImplTest, verifyCorrectBackgroundColorInQuad)
 
     const Color testColor = 0xFFA55AFF;
 
-    CCQuadList quadList;
+    MockCCQuadCuller quadCuller;
     IntSize layerSize = IntSize(100, 100);
     IntRect visibleLayerRect = IntRect(IntPoint(), layerSize);
 
@@ -72,10 +73,10 @@ TEST(CCSolidColorLayerImplTest, verifyCorrectBackgroundColorInQuad)
     layer->setBackgroundColor(testColor);
 
     OwnPtr<CCSharedQuadState> sharedQuadState = layer->createSharedQuadState();
-    layer->appendQuads(quadList, sharedQuadState.get());
+    layer->appendQuads(quadCuller, sharedQuadState.get());
 
-    ASSERT_EQ(quadList.size(), 1U);
-    EXPECT_EQ(quadList[0]->toSolidColorDrawQuad()->color(), testColor);
+    ASSERT_EQ(quadCuller.quadList().size(), 1U);
+    EXPECT_EQ(quadCuller.quadList()[0]->toSolidColorDrawQuad()->color(), testColor);
 }
 
 } // namespace
index ff7daa3..fe8ca8e 100644 (file)
@@ -27,6 +27,7 @@
 #include "cc/CCTiledLayerImpl.h"
 
 #include "CCLayerTestCommon.h"
+#include "MockCCQuadCuller.h"
 #include "cc/CCSingleThreadProxy.h"
 #include "cc/CCTileDrawQuad.h"
 #include <gmock/gmock.h>
@@ -69,11 +70,11 @@ TEST(CCTiledLayerImplTest, emptyQuadList)
     // Verify default layer does creates quads
     {
         OwnPtr<CCTiledLayerImpl> layer = createLayer(tileSize, layerSize, CCLayerTilingData::NoBorderTexels);
-        CCQuadList quads;
+        MockCCQuadCuller quadCuller;
         OwnPtr<CCSharedQuadState> sharedQuadState = layer->createSharedQuadState();
-        layer->appendQuads(quads, sharedQuadState.get());
+        layer->appendQuads(quadCuller, sharedQuadState.get());
         const unsigned numTiles = numTilesX * numTilesY;
-        EXPECT_EQ(quads.size(), numTiles);
+        EXPECT_EQ(quadCuller.quadList().size(), numTiles);
     }
 
     // Layer with empty visible layer rect produces no quads
@@ -81,10 +82,10 @@ TEST(CCTiledLayerImplTest, emptyQuadList)
         OwnPtr<CCTiledLayerImpl> layer = createLayer(tileSize, layerSize, CCLayerTilingData::NoBorderTexels);
         layer->setVisibleLayerRect(IntRect());
 
-        CCQuadList quads;
+        MockCCQuadCuller quadCuller;
         OwnPtr<CCSharedQuadState> sharedQuadState = layer->createSharedQuadState();
-        layer->appendQuads(quads, sharedQuadState.get());
-        EXPECT_EQ(quads.size(), 0u);
+        layer->appendQuads(quadCuller, sharedQuadState.get());
+        EXPECT_EQ(quadCuller.quadList().size(), 0u);
     }
 
     // Layer with non-intersecting visible layer rect produces no quads
@@ -94,10 +95,10 @@ TEST(CCTiledLayerImplTest, emptyQuadList)
         IntRect outsideBounds(IntPoint(-100, -100), IntSize(50, 50));
         layer->setVisibleLayerRect(outsideBounds);
 
-        CCQuadList quads;
+        MockCCQuadCuller quadCuller;
         OwnPtr<CCSharedQuadState> sharedQuadState = layer->createSharedQuadState();
-        layer->appendQuads(quads, sharedQuadState.get());
-        EXPECT_EQ(quads.size(), 0u);
+        layer->appendQuads(quadCuller, sharedQuadState.get());
+        EXPECT_EQ(quadCuller.quadList().size(), 0u);
     }
 
     // Layer with skips draw produces no quads
@@ -105,10 +106,10 @@ TEST(CCTiledLayerImplTest, emptyQuadList)
         OwnPtr<CCTiledLayerImpl> layer = createLayer(tileSize, layerSize, CCLayerTilingData::NoBorderTexels);
         layer->setSkipsDraw(true);
 
-        CCQuadList quads;
+        MockCCQuadCuller quadCuller;
         OwnPtr<CCSharedQuadState> sharedQuadState = layer->createSharedQuadState();
-        layer->appendQuads(quads, sharedQuadState.get());
-        EXPECT_EQ(quads.size(), 0u);
+        layer->appendQuads(quadCuller, sharedQuadState.get());
+        EXPECT_EQ(quadCuller.quadList().size(), 0u);
     }
 }
 
@@ -126,12 +127,12 @@ TEST(CCTiledLayerImplTest, checkerboarding)
 
     // No checkerboarding
     {
-        CCQuadList quads;
-        layer->appendQuads(quads, sharedQuadState.get());
-        EXPECT_EQ(quads.size(), 4u);
+        MockCCQuadCuller quadCuller;
+        layer->appendQuads(quadCuller, sharedQuadState.get());
+        EXPECT_EQ(quadCuller.quadList().size(), 4u);
 
-        for (size_t i = 0; i < quads.size(); ++i)
-            EXPECT_EQ(quads[i]->material(), CCDrawQuad::TiledContent);
+        for (size_t i = 0; i < quadCuller.quadList().size(); ++i)
+            EXPECT_EQ(quadCuller.quadList()[i]->material(), CCDrawQuad::TiledContent);
     }
 
     for (int i = 0; i < numTilesX; ++i)
@@ -140,11 +141,11 @@ TEST(CCTiledLayerImplTest, checkerboarding)
 
     // All checkerboarding
     {
-        CCQuadList quads;
-        layer->appendQuads(quads, sharedQuadState.get());
-        EXPECT_EQ(quads.size(), 4u);
-        for (size_t i = 0; i < quads.size(); ++i)
-            EXPECT_EQ(quads[i]->material(), CCDrawQuad::SolidColor);
+        MockCCQuadCuller quadCuller;
+        layer->appendQuads(quadCuller, sharedQuadState.get());
+        EXPECT_EQ(quadCuller.quadList().size(), 4u);
+        for (size_t i = 0; i < quadCuller.quadList().size(); ++i)
+            EXPECT_EQ(quadCuller.quadList()[i]->material(), CCDrawQuad::SolidColor);
     }
 }
 
@@ -154,8 +155,9 @@ static PassOwnPtr<CCSharedQuadState> getQuads(CCQuadList& quads, IntSize tileSiz
     layer->setVisibleLayerRect(visibleLayerRect);
     layer->setBounds(layerSize);
 
+    MockCCQuadCuller quadCuller(quads);
     OwnPtr<CCSharedQuadState> sharedQuadState = layer->createSharedQuadState();
-    layer->appendQuads(quads, sharedQuadState.get());
+    layer->appendQuads(quadCuller, sharedQuadState.get());
     return sharedQuadState.release(); // The shared data must be owned as long as the quad list exists.
 }
 
@@ -272,12 +274,12 @@ TEST(CCTiledLayerImplTest, backgroundCoversViewport)
 
         OwnPtr<CCSharedQuadState> sharedQuadState = layer->createSharedQuadState();
 
-        CCQuadList quads;
-        layer->appendQuads(quads, sharedQuadState.get());
-        EXPECT_EQ(quads.size(), numTiles);
+        MockCCQuadCuller quadCuller;
+        layer->appendQuads(quadCuller, sharedQuadState.get());
+        EXPECT_EQ(quadCuller.quadList().size(), numTiles);
 
-        for (size_t i = 0; i < quads.size(); ++i)
-            EXPECT_EQ(quads[i]->material(), CCDrawQuad::TiledContent);
+        for (size_t i = 0; i < quadCuller.quadList().size(); ++i)
+            EXPECT_EQ(quadCuller.quadList()[i]->material(), CCDrawQuad::TiledContent);
     }
 
     // Empty visible content area (fullscreen gutter rect)
@@ -287,13 +289,13 @@ TEST(CCTiledLayerImplTest, backgroundCoversViewport)
         layer->setVisibleLayerRect(IntRect());
 
         OwnPtr<CCSharedQuadState> sharedQuadState = layer->createSharedQuadState();
-        CCQuadList quads;
-        layer->appendQuads(quads, sharedQuadState.get());
+        MockCCQuadCuller quadCuller;
+        layer->appendQuads(quadCuller, sharedQuadState.get());
 
-        for (size_t i = 0; i < quads.size(); ++i)
-            EXPECT_EQ(quads[i]->material(), CCDrawQuad::SolidColor);
+        for (size_t i = 0; i < quadCuller.quadList().size(); ++i)
+            EXPECT_EQ(quadCuller.quadList()[i]->material(), CCDrawQuad::SolidColor);
 
-        verifyQuadsExactlyCoverRect(quads, clipRect);
+        verifyQuadsExactlyCoverRect(quadCuller.quadList(), clipRect);
     }
 
     // Content area in middle of clip rect (four surrounding gutter rects)
@@ -303,20 +305,20 @@ TEST(CCTiledLayerImplTest, backgroundCoversViewport)
         layer->setVisibleLayerRect(IntRect(IntPoint(), layerSize));
 
         OwnPtr<CCSharedQuadState> sharedQuadState = layer->createSharedQuadState();
-        CCQuadList quads;
-        layer->appendQuads(quads, sharedQuadState.get());
+        MockCCQuadCuller quadCuller;
+        layer->appendQuads(quadCuller, sharedQuadState.get());
 
         unsigned numContentTiles = 0, numGutterTiles = 0;
-        for (size_t i = 0; i < quads.size(); ++i) {
-            if (quads[i]->material() == CCDrawQuad::TiledContent)
+        for (size_t i = 0; i < quadCuller.quadList().size(); ++i) {
+            if (quadCuller.quadList()[i]->material() == CCDrawQuad::TiledContent)
                 numContentTiles++;
-            else if (quads[i]->material() == CCDrawQuad::SolidColor)
+            else if (quadCuller.quadList()[i]->material() == CCDrawQuad::SolidColor)
                 numGutterTiles++;
         }
         EXPECT_EQ(numContentTiles, numTiles);
         EXPECT_GE(numGutterTiles, 4u);
 
-        verifyQuadsExactlyCoverRect(quads, clipRect);
+        verifyQuadsExactlyCoverRect(quadCuller.quadList(), clipRect);
     }
 }
 
diff --git a/Source/WebKit/chromium/tests/MockCCQuadCuller.h b/Source/WebKit/chromium/tests/MockCCQuadCuller.h
new file mode 100644 (file)
index 0000000..6dc72c5
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MockCCQuadCuller_h
+#define MockCCQuadCuller_h
+
+#include "IntRect.h"
+#include "cc/CCDrawQuad.h"
+#include "cc/CCQuadCuller.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class MockCCQuadCuller : public WebCore::CCQuadCuller {
+public:
+    MockCCQuadCuller()
+        : CCQuadCuller(m_quadListStorage, 0, 0, 0)
+        , m_activeQuadList(m_quadListStorage)
+    { }
+
+    explicit MockCCQuadCuller(CCQuadList& externalQuadList)
+        : CCQuadCuller(externalQuadList, 0, 0, 0)
+        , m_activeQuadList(externalQuadList)
+    { }
+
+    virtual void append(WTF::PassOwnPtr<WebCore::CCDrawQuad> newQuad)
+    {
+        OwnPtr<WebCore::CCDrawQuad> drawQuad = newQuad;
+        if (!drawQuad->quadRect().isEmpty())
+            m_activeQuadList.append(drawQuad.release());
+    }
+
+    const WebCore::CCQuadList& quadList() const { return m_activeQuadList; };
+
+private:
+    WebCore::CCQuadList& m_activeQuadList;
+    WebCore::CCQuadList m_quadListStorage;
+};
+
+} // namespace WebCore
+#endif // MockCCQuadCuller_h