diff options
Diffstat (limited to 'Source/WebKit/chromium/tests/CCLayerTreeHostImplTest.cpp')
-rw-r--r-- | Source/WebKit/chromium/tests/CCLayerTreeHostImplTest.cpp | 641 |
1 files changed, 544 insertions, 97 deletions
diff --git a/Source/WebKit/chromium/tests/CCLayerTreeHostImplTest.cpp b/Source/WebKit/chromium/tests/CCLayerTreeHostImplTest.cpp index d75c12890..ff2497085 100644 --- a/Source/WebKit/chromium/tests/CCLayerTreeHostImplTest.cpp +++ b/Source/WebKit/chromium/tests/CCLayerTreeHostImplTest.cpp @@ -26,16 +26,28 @@ #include "cc/CCLayerTreeHostImpl.h" +#include "CCAnimationTestCommon.h" +#include "CCLayerTestCommon.h" #include "FakeWebGraphicsContext3D.h" #include "GraphicsContext3DPrivate.h" #include "LayerRendererChromium.h" #include "cc/CCLayerImpl.h" +#include "cc/CCLayerTilingData.h" +#include "cc/CCQuadCuller.h" +#include "cc/CCScrollbarLayerImpl.h" #include "cc/CCSingleThreadProxy.h" -#include "cc/CCSolidColorDrawQuad.h" +#include "cc/CCTextureLayerImpl.h" +#include "cc/CCTileDrawQuad.h" +#include "cc/CCTiledLayerImpl.h" +#include "cc/CCVideoLayerImpl.h" #include <gtest/gtest.h> +#include <public/WebVideoFrame.h> +#include <public/WebVideoFrameProvider.h> +using namespace CCLayerTestCommon; using namespace WebCore; using namespace WebKit; +using namespace WebKitTests; namespace { @@ -49,11 +61,12 @@ public: m_hostImpl = CCLayerTreeHostImpl::create(settings, this); } - virtual void didLoseContextOnImplThread() { } - virtual void onSwapBuffersCompleteOnImplThread() { } - virtual void setNeedsRedrawOnImplThread() { m_didRequestRedraw = true; } - virtual void setNeedsCommitOnImplThread() { m_didRequestCommit = true; } - virtual void postAnimationEventsToMainThreadOnImplThread(PassOwnPtr<CCAnimationEventsVector>, double wallClockTime) { } + virtual void didLoseContextOnImplThread() OVERRIDE { } + virtual void onSwapBuffersCompleteOnImplThread() OVERRIDE { } + virtual void setNeedsRedrawOnImplThread() OVERRIDE { m_didRequestRedraw = true; } + virtual void setNeedsCommitOnImplThread() OVERRIDE { m_didRequestCommit = true; } + virtual void postAnimationEventsToMainThreadOnImplThread(PassOwnPtr<CCAnimationEventsVector>, double wallClockTime) OVERRIDE { } + virtual void postSetContentsMemoryAllocationLimitBytesToMainThreadOnImplThread(size_t) OVERRIDE { } static void expectClearedScrollDeltasRecursive(CCLayerImpl* layer) { @@ -250,7 +263,9 @@ TEST_F(CCLayerTreeHostImplTest, nonFastScrollableRegionWithOffset) root->setNonFastScrollableRegion(IntRect(0, 0, 50, 50)); root->setPosition(FloatPoint(-25, 0)); m_hostImpl->setRootLayer(root.release()); - m_hostImpl->drawLayers(); // Update draw transforms so we can correctly map points into layer space. + CCLayerTreeHostImpl::FrameData frame; + EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); + m_hostImpl->drawLayers(frame); // Update draw transforms so we can correctly map points into layer space. // This point would fall into the non-fast scrollable region except that we've moved the layer down by 25 pixels. EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(40, 10), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted); @@ -310,7 +325,7 @@ TEST_F(CCLayerTreeHostImplTest, pinchGesture) scrollLayer->setScrollDelta(IntSize()); scrollLayer->setScrollPosition(IntPoint(50, 50)); - float pageScaleDelta = 0.1; + float pageScaleDelta = 0.1f; m_hostImpl->pinchGestureBegin(); m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(0, 0)); m_hostImpl->pinchGestureEnd(); @@ -390,7 +405,7 @@ TEST_F(CCLayerTreeHostImplTest, pageScaleAnimation) } } -class DidDrawCheckLayer : public CCLayerImpl { +class DidDrawCheckLayer : public CCTiledLayerImpl { public: static PassOwnPtr<DidDrawCheckLayer> create(int id) { return adoptPtr(new DidDrawCheckLayer(id)); } @@ -407,9 +422,9 @@ public: bool didDrawCalled() const { return m_didDrawCalled; } bool willDrawCalled() const { return m_willDrawCalled; } -private: +protected: explicit DidDrawCheckLayer(int id) - : CCLayerImpl(id) + : CCTiledLayerImpl(id) , m_didDrawCalled(false) , m_willDrawCalled(false) { @@ -418,6 +433,7 @@ private: setDrawsContent(true); } +private: bool m_didDrawCalled; bool m_willDrawCalled; }; @@ -432,10 +448,14 @@ TEST_F(CCLayerTreeHostImplTest, didDrawNotCalledOnHiddenLayer) m_hostImpl->setRootLayer(DidDrawCheckLayer::create(0)); DidDrawCheckLayer* root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer()); + CCLayerTreeHostImpl::FrameData frame; + EXPECT_FALSE(root->willDrawCalled()); EXPECT_FALSE(root->didDrawCalled()); - m_hostImpl->drawLayers(); + EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); + m_hostImpl->drawLayers(frame); + m_hostImpl->didDrawAllLayers(frame); EXPECT_FALSE(root->willDrawCalled()); EXPECT_FALSE(root->didDrawCalled()); @@ -448,7 +468,9 @@ TEST_F(CCLayerTreeHostImplTest, didDrawNotCalledOnHiddenLayer) EXPECT_FALSE(root->willDrawCalled()); EXPECT_FALSE(root->didDrawCalled()); - m_hostImpl->drawLayers(); + EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); + m_hostImpl->drawLayers(frame); + m_hostImpl->didDrawAllLayers(frame); EXPECT_TRUE(root->willDrawCalled()); EXPECT_TRUE(root->didDrawCalled()); @@ -470,14 +492,17 @@ TEST_F(CCLayerTreeHostImplTest, didDrawCalledOnAllLayers) layer1->addChild(DidDrawCheckLayer::create(2)); DidDrawCheckLayer* layer2 = static_cast<DidDrawCheckLayer*>(layer1->children()[0].get()); - layer1->setOpacity(0.3); + layer1->setOpacity(0.3f); layer1->setPreserves3D(false); EXPECT_FALSE(root->didDrawCalled()); EXPECT_FALSE(layer1->didDrawCalled()); EXPECT_FALSE(layer2->didDrawCalled()); - m_hostImpl->drawLayers(); + CCLayerTreeHostImpl::FrameData frame; + EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); + m_hostImpl->drawLayers(frame); + m_hostImpl->didDrawAllLayers(frame); EXPECT_TRUE(root->didDrawCalled()); EXPECT_TRUE(layer1->didDrawCalled()); @@ -487,6 +512,71 @@ TEST_F(CCLayerTreeHostImplTest, didDrawCalledOnAllLayers) EXPECT_TRUE(!!layer1->renderSurface()); } +class MissingTextureAnimatingLayer : public DidDrawCheckLayer { +public: + static PassOwnPtr<MissingTextureAnimatingLayer> create(int id, bool tileMissing, bool skipsDraw, bool animating) { return adoptPtr(new MissingTextureAnimatingLayer(id, tileMissing, skipsDraw, animating)); } + +private: + explicit MissingTextureAnimatingLayer(int id, bool tileMissing, bool skipsDraw, bool animating) + : DidDrawCheckLayer(id) + { + OwnPtr<CCLayerTilingData> tilingData = CCLayerTilingData::create(IntSize(10, 10), CCLayerTilingData::NoBorderTexels); + tilingData->setBounds(bounds()); + setTilingData(*tilingData.get()); + setSkipsDraw(skipsDraw); + if (!tileMissing) + pushTileProperties(0, 0, 1, IntRect()); + if (animating) + addAnimatedTransformToLayer(*this, 10, 3, 0); + } +}; + +TEST_F(CCLayerTreeHostImplTest, prepareToDrawFailsWhenAnimationUsesCheckerboard) +{ + m_hostImpl->initializeLayerRenderer(createContext()); + m_hostImpl->setViewportSize(IntSize(10, 10)); + + // When the texture is not missing, we draw as usual. + m_hostImpl->setRootLayer(DidDrawCheckLayer::create(0)); + DidDrawCheckLayer* root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer()); + root->addChild(MissingTextureAnimatingLayer::create(1, false, false, true)); + + CCLayerTreeHostImpl::FrameData frame; + + EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); + m_hostImpl->drawLayers(frame); + m_hostImpl->didDrawAllLayers(frame); + + // When a texture is missing and we're not animating, we draw as usual with checkerboarding. + m_hostImpl->setRootLayer(DidDrawCheckLayer::create(0)); + root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer()); + root->addChild(MissingTextureAnimatingLayer::create(1, true, false, false)); + + EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); + m_hostImpl->drawLayers(frame); + m_hostImpl->didDrawAllLayers(frame); + + // When a texture is missing and we're animating, we don't want to draw anything. + m_hostImpl->setRootLayer(DidDrawCheckLayer::create(0)); + root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer()); + root->addChild(MissingTextureAnimatingLayer::create(1, true, false, true)); + + m_didRequestCommit = false; + EXPECT_FALSE(m_hostImpl->prepareToDraw(frame)); + EXPECT_TRUE(m_didRequestCommit); + m_hostImpl->drawLayers(frame); + m_hostImpl->didDrawAllLayers(frame); + + // When the layer skips draw and we're animating, we still draw the frame. + m_hostImpl->setRootLayer(DidDrawCheckLayer::create(0)); + root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer()); + root->addChild(MissingTextureAnimatingLayer::create(1, false, true, true)); + + EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); + m_hostImpl->drawLayers(frame); + m_hostImpl->didDrawAllLayers(frame); +} + class BlendStateTrackerContext: public FakeWebGraphicsContext3D { public: BlendStateTrackerContext() : m_blend(false) { } @@ -513,14 +603,20 @@ 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, bool&) OVERRIDE { m_quadsAppended = true; - Color color = m_opaqueColor ? Color::white : Color(0, 0, 0, 0); - OwnPtr<CCDrawQuad> testBlendingDrawQuad = CCSolidColorDrawQuad::create(sharedQuadState, IntRect(5, 5, 5, 5), color); + IntRect opaqueRect; + if (opaque() || m_opaqueContents) + opaqueRect = m_quadRect; + else + opaqueRect = m_opaqueContentRect; + OwnPtr<CCDrawQuad> testBlendingDrawQuad = CCTileDrawQuad::create(sharedQuadState, m_quadRect, opaqueRect, 0, IntPoint(), IntSize(1, 1), 0, false, false, false, false, false); + testBlendingDrawQuad->setQuadVisibleRect(m_quadVisibleRect); EXPECT_EQ(m_blend, testBlendingDrawQuad->needsBlending()); EXPECT_EQ(m_hasRenderSurface, !!renderSurface()); + quadList.append(testBlendingDrawQuad.release()); } void setExpectation(bool blend, bool hasRenderSurface) @@ -532,7 +628,10 @@ public: bool quadsAppended() const { return m_quadsAppended; } - void setOpaqueColor(bool opaqueColor) { m_opaqueColor = opaqueColor; } + void setQuadRect(const IntRect& rect) { m_quadRect = rect; } + void setQuadVisibleRect(const IntRect& rect) { m_quadVisibleRect = rect; } + void setOpaqueContents(bool opaque) { m_opaqueContents = opaque; } + void setOpaqueContentRect(const IntRect& rect) { m_opaqueContentRect = rect; } private: explicit BlendStateCheckLayer(int id) @@ -540,7 +639,9 @@ private: , m_blend(false) , m_hasRenderSurface(false) , m_quadsAppended(false) - , m_opaqueColor(true) + , m_opaqueContents(false) + , m_quadRect(5, 5, 5, 5) + , m_quadVisibleRect(5, 5, 5, 5) { setAnchorPoint(FloatPoint(0, 0)); setBounds(IntSize(10, 10)); @@ -550,7 +651,10 @@ private: bool m_blend; bool m_hasRenderSurface; bool m_quadsAppended; - bool m_opaqueColor; + bool m_opaqueContents; + IntRect m_quadRect; + IntRect m_opaqueContentRect; + IntRect m_quadVisibleRect; }; // https://bugs.webkit.org/show_bug.cgi?id=75783 @@ -571,78 +675,96 @@ TEST_F(CCLayerTreeHostImplTest, blendingOffWhenDrawingOpaqueLayers) root->addChild(BlendStateCheckLayer::create(1)); BlendStateCheckLayer* layer1 = static_cast<BlendStateCheckLayer*>(root->children()[0].get()); + CCLayerTreeHostImpl::FrameData frame; + // Opaque layer, drawn without blending. layer1->setOpaque(true); - layer1->setOpaqueColor(true); + layer1->setOpaqueContents(true); layer1->setExpectation(false, false); - m_hostImpl->drawLayers(); + EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); + m_hostImpl->drawLayers(frame); EXPECT_TRUE(layer1->quadsAppended()); + m_hostImpl->didDrawAllLayers(frame); - // Layer with translucent content, but solid color is opaque, so drawn without blending. + // Layer with translucent content, but opaque content, so drawn without blending. layer1->setOpaque(false); - layer1->setOpaqueColor(true); + layer1->setOpaqueContents(true); layer1->setExpectation(false, false); - m_hostImpl->drawLayers(); + EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); + m_hostImpl->drawLayers(frame); EXPECT_TRUE(layer1->quadsAppended()); + m_hostImpl->didDrawAllLayers(frame); // Layer with translucent content and painting, so drawn with blending. layer1->setOpaque(false); - layer1->setOpaqueColor(false); + layer1->setOpaqueContents(false); layer1->setExpectation(true, false); - m_hostImpl->drawLayers(); + EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); + m_hostImpl->drawLayers(frame); EXPECT_TRUE(layer1->quadsAppended()); + m_hostImpl->didDrawAllLayers(frame); // Layer with translucent opacity, drawn with blending. layer1->setOpaque(true); - layer1->setOpaqueColor(true); + layer1->setOpaqueContents(true); layer1->setOpacity(0.5); layer1->setExpectation(true, false); - m_hostImpl->drawLayers(); + EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); + m_hostImpl->drawLayers(frame); EXPECT_TRUE(layer1->quadsAppended()); + m_hostImpl->didDrawAllLayers(frame); // Layer with translucent opacity and painting, drawn with blending. layer1->setOpaque(true); - layer1->setOpaqueColor(false); + layer1->setOpaqueContents(false); layer1->setOpacity(0.5); layer1->setExpectation(true, false); - m_hostImpl->drawLayers(); + EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); + m_hostImpl->drawLayers(frame); EXPECT_TRUE(layer1->quadsAppended()); + m_hostImpl->didDrawAllLayers(frame); layer1->addChild(BlendStateCheckLayer::create(2)); BlendStateCheckLayer* layer2 = static_cast<BlendStateCheckLayer*>(layer1->children()[0].get()); // 2 opaque layers, drawn without blending. layer1->setOpaque(true); - layer1->setOpaqueColor(true); + layer1->setOpaqueContents(true); layer1->setOpacity(1); layer1->setExpectation(false, false); layer2->setOpaque(true); - layer2->setOpaqueColor(true); + layer2->setOpaqueContents(true); layer2->setOpacity(1); layer2->setExpectation(false, false); - m_hostImpl->drawLayers(); + EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); + m_hostImpl->drawLayers(frame); EXPECT_TRUE(layer1->quadsAppended()); EXPECT_TRUE(layer2->quadsAppended()); + m_hostImpl->didDrawAllLayers(frame); // Parent layer with translucent content, drawn with blending. // Child layer with opaque content, drawn without blending. layer1->setOpaque(false); - layer1->setOpaqueColor(false); + layer1->setOpaqueContents(false); layer1->setExpectation(true, false); layer2->setExpectation(false, false); - m_hostImpl->drawLayers(); + EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); + m_hostImpl->drawLayers(frame); EXPECT_TRUE(layer1->quadsAppended()); EXPECT_TRUE(layer2->quadsAppended()); + m_hostImpl->didDrawAllLayers(frame); // Parent layer with translucent content but opaque painting, drawn without blending. // Child layer with opaque content, drawn without blending. layer1->setOpaque(false); - layer1->setOpaqueColor(true); + layer1->setOpaqueContents(true); layer1->setExpectation(false, false); layer2->setExpectation(false, false); - m_hostImpl->drawLayers(); + EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); + m_hostImpl->drawLayers(frame); EXPECT_TRUE(layer1->quadsAppended()); EXPECT_TRUE(layer2->quadsAppended()); + m_hostImpl->didDrawAllLayers(frame); // Parent layer with translucent opacity and opaque content. Since it has a // drawing child, it's drawn to a render surface which carries the opacity, @@ -650,53 +772,196 @@ TEST_F(CCLayerTreeHostImplTest, blendingOffWhenDrawingOpaqueLayers) // Child layer with opaque content, drawn without blending (parent surface // carries the inherited opacity). layer1->setOpaque(true); - layer1->setOpaqueColor(true); + layer1->setOpaqueContents(true); layer1->setOpacity(0.5); layer1->setExpectation(false, true); layer2->setExpectation(false, false); - m_hostImpl->drawLayers(); + EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); + m_hostImpl->drawLayers(frame); EXPECT_TRUE(layer1->quadsAppended()); EXPECT_TRUE(layer2->quadsAppended()); + m_hostImpl->didDrawAllLayers(frame); // Draw again, but with child non-opaque, to make sure // layer1 not culled. layer1->setOpaque(true); - layer1->setOpaqueColor(true); + layer1->setOpaqueContents(true); layer1->setOpacity(1); layer1->setExpectation(false, false); layer2->setOpaque(true); - layer2->setOpaqueColor(true); + layer2->setOpaqueContents(true); layer2->setOpacity(0.5); layer2->setExpectation(true, false); - m_hostImpl->drawLayers(); + EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); + m_hostImpl->drawLayers(frame); EXPECT_TRUE(layer1->quadsAppended()); EXPECT_TRUE(layer2->quadsAppended()); + m_hostImpl->didDrawAllLayers(frame); // A second way of making the child non-opaque. layer1->setOpaque(true); layer1->setOpacity(1); layer1->setExpectation(false, false); layer2->setOpaque(false); - layer2->setOpaqueColor(false); + layer2->setOpaqueContents(false); layer2->setOpacity(1); layer2->setExpectation(true, false); - m_hostImpl->drawLayers(); + EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); + m_hostImpl->drawLayers(frame); EXPECT_TRUE(layer1->quadsAppended()); EXPECT_TRUE(layer2->quadsAppended()); + m_hostImpl->didDrawAllLayers(frame); // And when the layer says its not opaque but is painted opaque, it is not blended. layer1->setOpaque(true); layer1->setOpacity(1); layer1->setExpectation(false, false); layer2->setOpaque(false); - layer2->setOpaqueColor(true); + layer2->setOpaqueContents(true); layer2->setOpacity(1); layer2->setExpectation(false, false); - m_hostImpl->drawLayers(); + EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); + m_hostImpl->drawLayers(frame); EXPECT_TRUE(layer1->quadsAppended()); EXPECT_TRUE(layer2->quadsAppended()); + m_hostImpl->didDrawAllLayers(frame); + + // Layer with partially opaque contents, drawn with blending. + layer1->setOpaque(false); + layer1->setQuadRect(IntRect(5, 5, 5, 5)); + layer1->setQuadVisibleRect(IntRect(5, 5, 5, 5)); + layer1->setOpaqueContents(false); + layer1->setOpaqueContentRect(IntRect(5, 5, 2, 5)); + layer1->setExpectation(true, false); + EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); + m_hostImpl->drawLayers(frame); + EXPECT_TRUE(layer1->quadsAppended()); + m_hostImpl->didDrawAllLayers(frame); + + // Layer with partially opaque contents partially culled, drawn with blending. + layer1->setOpaque(false); + layer1->setQuadRect(IntRect(5, 5, 5, 5)); + layer1->setQuadVisibleRect(IntRect(5, 5, 5, 2)); + layer1->setOpaqueContents(false); + layer1->setOpaqueContentRect(IntRect(5, 5, 2, 5)); + layer1->setExpectation(true, false); + EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); + m_hostImpl->drawLayers(frame); + EXPECT_TRUE(layer1->quadsAppended()); + m_hostImpl->didDrawAllLayers(frame); + + // Layer with partially opaque contents culled, drawn with blending. + layer1->setOpaque(false); + layer1->setQuadRect(IntRect(5, 5, 5, 5)); + layer1->setQuadVisibleRect(IntRect(7, 5, 3, 5)); + layer1->setOpaqueContents(false); + layer1->setOpaqueContentRect(IntRect(5, 5, 2, 5)); + layer1->setExpectation(true, false); + EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); + m_hostImpl->drawLayers(frame); + EXPECT_TRUE(layer1->quadsAppended()); + m_hostImpl->didDrawAllLayers(frame); + + // Layer with partially opaque contents and translucent contents culled, drawn without blending. + layer1->setOpaque(false); + layer1->setQuadRect(IntRect(5, 5, 5, 5)); + layer1->setQuadVisibleRect(IntRect(5, 5, 2, 5)); + layer1->setOpaqueContents(false); + layer1->setOpaqueContentRect(IntRect(5, 5, 2, 5)); + layer1->setExpectation(false, false); + EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); + m_hostImpl->drawLayers(frame); + EXPECT_TRUE(layer1->quadsAppended()); + m_hostImpl->didDrawAllLayers(frame); + } +TEST_F(CCLayerTreeHostImplTest, viewportCovered) +{ + m_hostImpl->initializeLayerRenderer(createContext()); + m_hostImpl->setBackgroundColor(Color::gray); + + IntSize viewportSize(1000, 1000); + m_hostImpl->setViewportSize(viewportSize); + + m_hostImpl->setRootLayer(BlendStateCheckLayer::create(0)); + BlendStateCheckLayer* root = static_cast<BlendStateCheckLayer*>(m_hostImpl->rootLayer()); + root->setExpectation(false, true); + root->setOpaque(true); + + // No gutter rects + { + IntRect layerRect(0, 0, 1000, 1000); + root->setPosition(layerRect.location()); + root->setBounds(layerRect.size()); + root->setContentBounds(layerRect.size()); + root->setQuadRect(IntRect(IntPoint(), layerRect.size())); + root->setQuadVisibleRect(IntRect(IntPoint(), layerRect.size())); + + CCLayerTreeHostImpl::FrameData frame; + EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); + ASSERT_EQ(1u, frame.renderPasses.size()); + + size_t numGutterQuads = 0; + for (size_t i = 0; i < frame.renderPasses[0]->quadList().size(); ++i) + numGutterQuads += (frame.renderPasses[0]->quadList()[i]->material() == CCDrawQuad::SolidColor) ? 1 : 0; + EXPECT_EQ(0u, numGutterQuads); + EXPECT_EQ(1u, frame.renderPasses[0]->quadList().size()); + + verifyQuadsExactlyCoverRect(frame.renderPasses[0]->quadList(), IntRect(-layerRect.location(), viewportSize)); + m_hostImpl->didDrawAllLayers(frame); + } + + // Empty visible content area (fullscreen gutter rect) + { + IntRect layerRect(0, 0, 0, 0); + root->setPosition(layerRect.location()); + root->setBounds(layerRect.size()); + root->setContentBounds(layerRect.size()); + root->setQuadRect(IntRect(IntPoint(), layerRect.size())); + root->setQuadVisibleRect(IntRect(IntPoint(), layerRect.size())); + + CCLayerTreeHostImpl::FrameData frame; + EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); + ASSERT_EQ(1u, frame.renderPasses.size()); + m_hostImpl->didDrawAllLayers(frame); + + size_t numGutterQuads = 0; + for (size_t i = 0; i < frame.renderPasses[0]->quadList().size(); ++i) + numGutterQuads += (frame.renderPasses[0]->quadList()[i]->material() == CCDrawQuad::SolidColor) ? 1 : 0; + EXPECT_EQ(1u, numGutterQuads); + EXPECT_EQ(1u, frame.renderPasses[0]->quadList().size()); + + verifyQuadsExactlyCoverRect(frame.renderPasses[0]->quadList(), IntRect(-layerRect.location(), viewportSize)); + m_hostImpl->didDrawAllLayers(frame); + } + + // Content area in middle of clip rect (four surrounding gutter rects) + { + IntRect layerRect(500, 500, 200, 200); + root->setPosition(layerRect.location()); + root->setBounds(layerRect.size()); + root->setContentBounds(layerRect.size()); + root->setQuadRect(IntRect(IntPoint(), layerRect.size())); + root->setQuadVisibleRect(IntRect(IntPoint(), layerRect.size())); + + CCLayerTreeHostImpl::FrameData frame; + EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); + ASSERT_EQ(1u, frame.renderPasses.size()); + + size_t numGutterQuads = 0; + for (size_t i = 0; i < frame.renderPasses[0]->quadList().size(); ++i) + numGutterQuads += (frame.renderPasses[0]->quadList()[i]->material() == CCDrawQuad::SolidColor) ? 1 : 0; + EXPECT_EQ(4u, numGutterQuads); + EXPECT_EQ(5u, frame.renderPasses[0]->quadList().size()); + + verifyQuadsExactlyCoverRect(frame.renderPasses[0]->quadList(), IntRect(-layerRect.location(), viewportSize)); + m_hostImpl->didDrawAllLayers(frame); + } + +} + + class ReshapeTrackerContext: public FakeWebGraphicsContext3D { public: ReshapeTrackerContext() : m_reshapeCalled(false) { } @@ -734,8 +999,11 @@ TEST_F(CCLayerTreeHostImplTest, reshapeNotCalledUntilDraw) m_hostImpl->setRootLayer(adoptPtr(root)); EXPECT_FALSE(reshapeTracker->reshapeCalled()); - m_hostImpl->drawLayers(); + CCLayerTreeHostImpl::FrameData frame; + EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); + m_hostImpl->drawLayers(frame); EXPECT_TRUE(reshapeTracker->reshapeCalled()); + m_hostImpl->didDrawAllLayers(frame); } class PartialSwapTrackerContext : public FakeWebGraphicsContext3D { @@ -786,8 +1054,12 @@ TEST_F(CCLayerTreeHostImplTest, partialSwapReceivesDamageRect) root->addChild(adoptPtr(child)); layerTreeHostImpl->setRootLayer(adoptPtr(root)); + CCLayerTreeHostImpl::FrameData frame; + // First frame, the entire screen should get swapped. - layerTreeHostImpl->drawLayers(); + EXPECT_TRUE(layerTreeHostImpl->prepareToDraw(frame)); + layerTreeHostImpl->drawLayers(frame); + layerTreeHostImpl->didDrawAllLayers(frame); layerTreeHostImpl->swapBuffers(); IntRect actualSwapRect = partialSwapTracker->partialSwapRect(); IntRect expectedSwapRect = IntRect(IntPoint::zero(), IntSize(500, 500)); @@ -801,7 +1073,9 @@ TEST_F(CCLayerTreeHostImplTest, partialSwapReceivesDamageRect) // expected damage rect: IntRect(IntPoint::zero(), IntSize(26, 28)); // expected swap rect: vertically flipped, with origin at bottom left corner. child->setPosition(FloatPoint(0, 0)); - layerTreeHostImpl->drawLayers(); + EXPECT_TRUE(layerTreeHostImpl->prepareToDraw(frame)); + layerTreeHostImpl->drawLayers(frame); + m_hostImpl->didDrawAllLayers(frame); layerTreeHostImpl->swapBuffers(); actualSwapRect = partialSwapTracker->partialSwapRect(); expectedSwapRect = IntRect(IntPoint(0, 500-28), IntSize(26, 28)); @@ -814,8 +1088,10 @@ TEST_F(CCLayerTreeHostImplTest, partialSwapReceivesDamageRect) // expected damage rect: IntRect(IntPoint::zero(), IntSize(500, 500)); // expected swap rect: flipped damage rect, but also clamped to viewport layerTreeHostImpl->setViewportSize(IntSize(10, 10)); - root->setOpacity(0.7); // this will damage everything - layerTreeHostImpl->drawLayers(); + root->setOpacity(0.7f); // this will damage everything + EXPECT_TRUE(layerTreeHostImpl->prepareToDraw(frame)); + layerTreeHostImpl->drawLayers(frame); + m_hostImpl->didDrawAllLayers(frame); layerTreeHostImpl->swapBuffers(); actualSwapRect = partialSwapTracker->partialSwapRect(); expectedSwapRect = IntRect(IntPoint::zero(), IntSize(10, 10)); @@ -825,55 +1101,12 @@ TEST_F(CCLayerTreeHostImplTest, partialSwapReceivesDamageRect) EXPECT_EQ(expectedSwapRect.height(), actualSwapRect.height()); } -// Make sure that we reset damage tracking on visibility change because the -// state of the front buffer that we push to with PostSubBuffer is undefined. -TEST_F(CCLayerTreeHostImplTest, visibilityChangeResetsDamage) -{ - PartialSwapTrackerContext* partialSwapTracker = new PartialSwapTrackerContext(); - RefPtr<GraphicsContext3D> context = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(partialSwapTracker), GraphicsContext3D::RenderDirectlyToHostWindow); - - // This test creates its own CCLayerTreeHostImpl, so - // that we can force partial swap enabled. - CCSettings settings; - settings.partialSwapEnabled = true; - OwnPtr<CCLayerTreeHostImpl> layerTreeHostImpl = CCLayerTreeHostImpl::create(settings, this); - layerTreeHostImpl->initializeLayerRenderer(context); - layerTreeHostImpl->setViewportSize(IntSize(500, 500)); - - CCLayerImpl* root = new FakeDrawableCCLayerImpl(1); - root->setAnchorPoint(FloatPoint(0, 0)); - root->setBounds(IntSize(500, 500)); - root->setDrawsContent(true); - layerTreeHostImpl->setRootLayer(adoptPtr(root)); - - // First frame: ignore. - layerTreeHostImpl->drawLayers(); - layerTreeHostImpl->swapBuffers(); - - // Second frame: nothing has changed --- so we souldn't push anything with partial swap. - layerTreeHostImpl->drawLayers(); - layerTreeHostImpl->swapBuffers(); - EXPECT_TRUE(partialSwapTracker->partialSwapRect().isEmpty()); - - // Third frame: visibility change --- so we should push a full frame with partial swap. - layerTreeHostImpl->setVisible(false); - layerTreeHostImpl->setVisible(true); - layerTreeHostImpl->drawLayers(); - layerTreeHostImpl->swapBuffers(); - IntRect actualSwapRect = partialSwapTracker->partialSwapRect(); - IntRect expectedSwapRect = IntRect(IntPoint::zero(), IntSize(500, 500)); - EXPECT_EQ(expectedSwapRect.x(), actualSwapRect.x()); - EXPECT_EQ(expectedSwapRect.y(), actualSwapRect.y()); - EXPECT_EQ(expectedSwapRect.width(), actualSwapRect.width()); - EXPECT_EQ(expectedSwapRect.height(), actualSwapRect.height()); -} - // Make sure that context lost notifications are propagated through the tree. class ContextLostNotificationCheckLayer : public CCLayerImpl { public: static PassOwnPtr<ContextLostNotificationCheckLayer> create(int id) { return adoptPtr(new ContextLostNotificationCheckLayer(id)); } - virtual void didLoseContext() + virtual void didLoseContext() OVERRIDE { m_didLoseContextCalled = true; } @@ -927,4 +1160,218 @@ TEST_F(CCLayerTreeHostImplTest, finishAllRenderingAfterContextLost) m_hostImpl->finishAllRendering(); } +class ScrollbarLayerFakePaint : public CCScrollbarLayerImpl { +public: + static PassOwnPtr<ScrollbarLayerFakePaint> create(int id) { return adoptPtr(new ScrollbarLayerFakePaint(id)); } + + virtual void paint(GraphicsContext*) { } + +private: + ScrollbarLayerFakePaint(int id) : CCScrollbarLayerImpl(id) { } +}; + +TEST_F(CCLayerTreeHostImplTest, scrollbarLayerLostContext) +{ + m_hostImpl->initializeLayerRenderer(createContext()); + m_hostImpl->setViewportSize(IntSize(10, 10)); + + m_hostImpl->setRootLayer(ScrollbarLayerFakePaint::create(0)); + ScrollbarLayerFakePaint* scrollbar = static_cast<ScrollbarLayerFakePaint*>(m_hostImpl->rootLayer()); + scrollbar->setBounds(IntSize(1, 1)); + scrollbar->setContentBounds(IntSize(1, 1)); + scrollbar->setDrawsContent(true); + + for (int i = 0; i < 2; ++i) { + CCLayerTreeHostImpl::FrameData frame; + EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); + ASSERT(frame.renderPasses.size() == 1); + CCRenderPass* renderPass = frame.renderPasses[0].get(); + // Scrollbar layer should always generate quads, even after lost context + EXPECT_GT(renderPass->quadList().size(), 0u); + m_hostImpl->didDrawAllLayers(frame); + m_hostImpl->initializeLayerRenderer(createContext()); + } +} + +// Fake WebGraphicsContext3D that will cause a failure if trying to use a +// resource that wasn't created by it (resources created by +// FakeWebGraphicsContext3D have an id of 1). +class StrictWebGraphicsContext3D : public FakeWebGraphicsContext3D { +public: + virtual WebGLId createBuffer() { return 2; } + virtual WebGLId createFramebuffer() { return 3; } + virtual WebGLId createProgram() { return 4; } + virtual WebGLId createRenderbuffer() { return 5; } + virtual WebGLId createShader(WGC3Denum) { return 6; } + virtual WebGLId createTexture() { return 7; } + + virtual void deleteBuffer(WebGLId id) + { + if (id != 2) + ADD_FAILURE() << "Trying to delete buffer id " << id; + } + + virtual void deleteFramebuffer(WebGLId id) + { + if (id != 3) + ADD_FAILURE() << "Trying to delete framebuffer id " << id; + } + + virtual void deleteProgram(WebGLId id) + { + if (id != 4) + ADD_FAILURE() << "Trying to delete program id " << id; + } + + virtual void deleteRenderbuffer(WebGLId id) + { + if (id != 5) + ADD_FAILURE() << "Trying to delete renderbuffer id " << id; + } + + virtual void deleteShader(WebGLId id) + { + if (id != 6) + ADD_FAILURE() << "Trying to delete shader id " << id; + } + + virtual void deleteTexture(WebGLId id) + { + if (id != 7) + ADD_FAILURE() << "Trying to delete texture id " << id; + } + + virtual void bindBuffer(WGC3Denum, WebGLId id) + { + if (id != 2 && id) + ADD_FAILURE() << "Trying to bind buffer id " << id; + } + + virtual void bindFramebuffer(WGC3Denum, WebGLId id) + { + if (id != 3 && id) + ADD_FAILURE() << "Trying to bind framebuffer id " << id; + } + + virtual void useProgram(WebGLId id) + { + if (id != 4) + ADD_FAILURE() << "Trying to use program id " << id; + } + + virtual void bindRenderbuffer(WGC3Denum, WebGLId id) + { + if (id != 5 && id) + ADD_FAILURE() << "Trying to bind renderbuffer id " << id; + } + + virtual void attachShader(WebGLId program, WebGLId shader) + { + if ((program != 4) || (shader != 6)) + ADD_FAILURE() << "Trying to attach shader id " << shader << " to program id " << program; + } + + virtual void bindTexture(WGC3Denum, WebGLId id) + { + if (id != 7 && id) + ADD_FAILURE() << "Trying to bind texture id " << id; + } + + static PassRefPtr<GraphicsContext3D> createGraphicsContext() + { + return GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new StrictWebGraphicsContext3D()), GraphicsContext3D::RenderDirectlyToHostWindow); + } +}; + +// Fake video frame that represents a 4x4 YUV video frame. +class FakeVideoFrame: public WebVideoFrame { +public: + FakeVideoFrame() { memset(m_data, 0x80, sizeof(m_data)); } + virtual ~FakeVideoFrame() { } + virtual Format format() const { return FormatYV12; } + virtual unsigned width() const { return 4; } + virtual unsigned height() const { return 4; } + virtual unsigned planes() const { return 3; } + virtual int stride(unsigned plane) const { return 4; } + virtual const void* data(unsigned plane) const { return m_data; } + virtual unsigned textureId() const { return 0; } + virtual unsigned textureTarget() const { return 0; } + +private: + char m_data[16]; +}; + +// Fake video frame provider that always provides the same FakeVideoFrame. +class FakeVideoFrameProvider: public WebVideoFrameProvider { +public: + FakeVideoFrameProvider() : m_client(0) { } + virtual ~FakeVideoFrameProvider() + { + if (m_client) + m_client->stopUsingProvider(); + } + + virtual void setVideoFrameProviderClient(Client* client) { m_client = client; } + virtual WebVideoFrame* getCurrentFrame() { return &m_frame; } + virtual void putCurrentFrame(WebVideoFrame*) { } + +private: + FakeVideoFrame m_frame; + Client* m_client; +}; + +TEST_F(CCLayerTreeHostImplTest, dontUseOldResourcesAfterLostContext) +{ + m_hostImpl->initializeLayerRenderer(createContext()); + m_hostImpl->setViewportSize(IntSize(10, 10)); + + OwnPtr<CCLayerImpl> rootLayer(CCLayerImpl::create(0)); + rootLayer->setBounds(IntSize(10, 10)); + rootLayer->setAnchorPoint(FloatPoint(0, 0)); + + OwnPtr<CCTiledLayerImpl> tileLayer = CCTiledLayerImpl::create(1); + tileLayer->setBounds(IntSize(10, 10)); + tileLayer->setAnchorPoint(FloatPoint(0, 0)); + tileLayer->setContentBounds(IntSize(10, 10)); + tileLayer->setDrawsContent(true); + tileLayer->setSkipsDraw(false); + OwnPtr<CCLayerTilingData> tilingData(CCLayerTilingData::create(IntSize(10, 10), CCLayerTilingData::NoBorderTexels)); + tilingData->setBounds(IntSize(10, 10)); + tileLayer->setTilingData(*tilingData); + tileLayer->pushTileProperties(0, 0, 1, IntRect(0, 0, 10, 10)); + rootLayer->addChild(tileLayer.release()); + + OwnPtr<CCTextureLayerImpl> textureLayer = CCTextureLayerImpl::create(2); + textureLayer->setBounds(IntSize(10, 10)); + textureLayer->setAnchorPoint(FloatPoint(0, 0)); + textureLayer->setContentBounds(IntSize(10, 10)); + textureLayer->setDrawsContent(true); + textureLayer->setTextureId(1); + rootLayer->addChild(textureLayer.release()); + + FakeVideoFrameProvider provider; + OwnPtr<CCVideoLayerImpl> videoLayer = CCVideoLayerImpl::create(3, &provider); + videoLayer->setBounds(IntSize(10, 10)); + videoLayer->setAnchorPoint(FloatPoint(0, 0)); + videoLayer->setContentBounds(IntSize(10, 10)); + videoLayer->setDrawsContent(true); + rootLayer->addChild(videoLayer.release()); + + m_hostImpl->setRootLayer(rootLayer.release()); + + CCLayerTreeHostImpl::FrameData frame; + EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); + m_hostImpl->drawLayers(frame); + m_hostImpl->didDrawAllLayers(frame); + m_hostImpl->swapBuffers(); + + // Lose the context, replacing it with a StrictWebGraphicsContext3D, that + // will warn if any resource from the previous context gets used. + m_hostImpl->initializeLayerRenderer(StrictWebGraphicsContext3D::createGraphicsContext()); + EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); + m_hostImpl->drawLayers(frame); + m_hostImpl->didDrawAllLayers(frame); + m_hostImpl->swapBuffers(); +} + } // namespace |