diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-02-03 09:55:33 +0100 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-02-03 09:55:33 +0100 |
commit | cd44dc59cdfc39534aef4d417e9f3c412e3be139 (patch) | |
tree | 8d89889ba95ed6ec9322e733846cc9cce9d7dff1 /Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp | |
parent | d11f84f5b5cdc0d92a08af01b13472fdd5f9acb9 (diff) | |
download | qtwebkit-cd44dc59cdfc39534aef4d417e9f3c412e3be139.tar.gz |
Imported WebKit commit fce473cb4d55aa9fe9d0b0322a2fffecb731b961 (http://svn.webkit.org/repository/webkit/trunk@106560)
Diffstat (limited to 'Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp')
-rw-r--r-- | Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp | 311 |
1 files changed, 308 insertions, 3 deletions
diff --git a/Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp b/Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp index 93e2ee8be..b0350db49 100644 --- a/Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp +++ b/Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp @@ -26,8 +26,12 @@ #include "TiledLayerChromium.h" +#include "CCLayerTreeTestCommon.h" +#include "FakeCCLayerTreeHostClient.h" #include "LayerTextureUpdater.h" +#include "Region.h" #include "TextureManager.h" +#include "WebCompositor.h" #include "cc/CCSingleThreadProxy.h" // For DebugScopedSetImplThread #include "cc/CCTextureUpdater.h" #include "cc/CCTiledLayerImpl.h" @@ -36,6 +40,12 @@ using namespace WebCore; using namespace WTF; +#define EXPECT_EQ_RECT(a, b) \ + EXPECT_EQ(a.x(), b.x()); \ + EXPECT_EQ(a.y(), b.y()); \ + EXPECT_EQ(a.width(), b.width()); \ + EXPECT_EQ(a.height(), b.height()); + namespace { class FakeTextureAllocator : public TextureAllocator { @@ -44,6 +54,8 @@ public: virtual void deleteTexture(unsigned, const IntSize&, GC3Denum) { } }; +class FakeTiledLayerChromium; + class FakeLayerTextureUpdater : public LayerTextureUpdater { public: class Texture : public LayerTextureUpdater::Texture { @@ -54,12 +66,32 @@ public: virtual void updateRect(GraphicsContext3D*, TextureAllocator*, const IntRect&, const IntRect&) { } }; - FakeLayerTextureUpdater() { } + FakeLayerTextureUpdater() : m_prepareCount(0) { } virtual ~FakeLayerTextureUpdater() { } + // Sets the rect to invalidate during the next call to prepareToUpdate(). After the next + // call to prepareToUpdate() the rect is reset. + void setRectToInvalidate(const IntRect&, FakeTiledLayerChromium*); + + // Number of times prepareToUpdate has been invoked. + int prepareCount() const { return m_prepareCount; } + void clearPrepareCount() { m_prepareCount = 0; } + + void setOpaquePaintRect(const IntRect& opaquePaintRect) { m_opaquePaintRect = opaquePaintRect; } + + // Last rect passed to prepareToUpdate(). + const IntRect& lastUpdateRect() const { return m_lastUpdateRect; } + virtual PassOwnPtr<LayerTextureUpdater::Texture> createTexture(TextureManager* manager) { return adoptPtr(new Texture(ManagedTexture::create(manager))); } virtual SampledTexelFormat sampledTexelFormat(GC3Denum) { return SampledTexelFormatRGBA; } - virtual void prepareToUpdate(const IntRect&, const IntSize&, int, float) { } + virtual void prepareToUpdate(const IntRect& contentRect, const IntSize&, int, float, IntRect* resultingOpaqueRect); + +private: + int m_prepareCount; + IntRect m_rectToInvalidate; + IntRect m_lastUpdateRect; + IntRect m_opaquePaintRect; + RefPtr<FakeTiledLayerChromium> m_layer; }; class FakeCCTiledLayerImpl : public CCTiledLayerImpl { @@ -77,7 +109,7 @@ public: class FakeTiledLayerChromium : public TiledLayerChromium { public: explicit FakeTiledLayerChromium(TextureManager* textureManager) - : TiledLayerChromium(0) + : TiledLayerChromium() , m_fakeTextureUpdater(adoptRef(new FakeLayerTextureUpdater)) , m_textureManager(textureManager) { @@ -108,8 +140,20 @@ public: return TiledLayerChromium::needsIdlePaint(rect); } + bool skipsDraw() const + { + return TiledLayerChromium::skipsDraw(); + } + + FakeLayerTextureUpdater* fakeLayerTextureUpdater() { return m_fakeTextureUpdater.get(); } + virtual TextureManager* textureManager() const { return m_textureManager; } + virtual void paintContentsIfDirty(const Region& /* occludedScreenSpace */) + { + prepareToUpdate(visibleLayerRect()); + } + private: virtual void createTextureUpdater(const CCLayerTreeHost*) { } @@ -122,6 +166,40 @@ private: TextureManager* m_textureManager; }; +class FakeTiledLayerWithScaledBounds : public FakeTiledLayerChromium { +public: + explicit FakeTiledLayerWithScaledBounds(TextureManager* textureManager) + : FakeTiledLayerChromium(textureManager) + { + } + + void setContentBounds(const IntSize& contentBounds) { m_forcedContentBounds = contentBounds; } + virtual IntSize contentBounds() const { return m_forcedContentBounds; } + + FloatRect updateRect() { return m_updateRect; } + +protected: + IntSize m_forcedContentBounds; +}; + +void FakeLayerTextureUpdater::setRectToInvalidate(const IntRect& rect, FakeTiledLayerChromium* layer) +{ + m_rectToInvalidate = rect; + m_layer = layer; +} + +void FakeLayerTextureUpdater::prepareToUpdate(const IntRect& contentRect, const IntSize&, int, float, IntRect* resultingOpaqueRect) +{ + m_prepareCount++; + m_lastUpdateRect = contentRect; + if (!m_rectToInvalidate.isEmpty()) { + m_layer->invalidateRect(m_rectToInvalidate); + m_rectToInvalidate = IntRect(); + m_layer = 0; + } + *resultingOpaqueRect = m_opaquePaintRect; +} + TEST(TiledLayerChromiumTest, pushDirtyTiles) { OwnPtr<TextureManager> textureManager = TextureManager::create(4*1024*1024, 2*1024*1024, 1024); @@ -259,4 +337,231 @@ TEST(TiledLayerChromiumTest, idlePaintOutOfMemory) layer->pushPropertiesTo(layerImpl.get()); } +TEST(TiledLayerChromiumTest, invalidateFromPrepare) +{ + OwnPtr<TextureManager> textureManager = TextureManager::create(4*1024*1024, 2*1024*1024, 1024); + RefPtr<FakeTiledLayerChromium> layer = adoptRef(new FakeTiledLayerChromium(textureManager.get())); + DebugScopedSetImplThread implThread; + RefPtr<FakeCCTiledLayerImpl> layerImpl = adoptRef(new FakeCCTiledLayerImpl(0)); + + FakeTextureAllocator textureAllocator; + CCTextureUpdater updater(&textureAllocator); + + // The tile size is 100x100, so this invalidates and then paints two tiles. + layer->setBounds(IntSize(100, 200)); + layer->invalidateRect(IntRect(0, 0, 100, 200)); + layer->prepareToUpdate(IntRect(0, 0, 100, 200)); + layer->updateCompositorResources(0, updater); + layer->pushPropertiesTo(layerImpl.get()); + + // We should have both tiles on the impl side. + EXPECT_TRUE(layerImpl->hasTileAt(0, 0)); + EXPECT_TRUE(layerImpl->hasTileAt(0, 1)); + + textureManager->unprotectAllTextures(); + + layer->fakeLayerTextureUpdater()->clearPrepareCount(); + // Invoke prepareToUpdate again. As the layer is valid prepareToUpdate shouldn't be invoked on + // the LayerTextureUpdater. + layer->prepareToUpdate(IntRect(0, 0, 100, 200)); + EXPECT_EQ(0, layer->fakeLayerTextureUpdater()->prepareCount()); + + layer->invalidateRect(IntRect(0, 0, 50, 50)); + // setRectToInvalidate triggers invalidateRect() being invoked from prepareToUpdate. + layer->fakeLayerTextureUpdater()->setRectToInvalidate(IntRect(25, 25, 50, 50), layer.get()); + layer->fakeLayerTextureUpdater()->clearPrepareCount(); + layer->prepareToUpdate(IntRect(0, 0, 100, 200)); + EXPECT_EQ(1, layer->fakeLayerTextureUpdater()->prepareCount()); + layer->fakeLayerTextureUpdater()->clearPrepareCount(); + // The layer should still be invalid as prepareToUpdate invoked invalidate. + layer->prepareToUpdate(IntRect(0, 0, 100, 200)); + EXPECT_EQ(1, layer->fakeLayerTextureUpdater()->prepareCount()); +} + +TEST(TiledLayerChromiumTest, verifyUpdateRectWhenContentBoundsAreScaled) +{ + // The updateRect (that indicates what was actually painted) should be in + // layer space, not the content space. + + OwnPtr<TextureManager> textureManager = TextureManager::create(4*1024*1024, 2*1024*1024, 1024); + RefPtr<FakeTiledLayerWithScaledBounds> layer = adoptRef(new FakeTiledLayerWithScaledBounds(textureManager.get())); + + FakeTextureAllocator textureAllocator; + CCTextureUpdater updater(&textureAllocator); + + IntRect layerBounds(0, 0, 300, 200); + IntRect contentBounds(0, 0, 200, 250); + + layer->setBounds(layerBounds.size()); + layer->setContentBounds(contentBounds.size()); + layer->setVisibleLayerRect(contentBounds); + + // On first update, the updateRect includes all tiles, even beyond the boundaries of the layer. + // However, it should still be in layer space, not content space. + layer->invalidateRect(contentBounds); + layer->prepareToUpdate(contentBounds); + layer->updateCompositorResources(0, updater); + EXPECT_FLOAT_RECT_EQ(FloatRect(0, 0, 300, 300 * 0.8), layer->updateRect()); + + // After the tiles are updated once, another invalidate only needs to update the bounds of the layer. + layer->invalidateRect(contentBounds); + layer->prepareToUpdate(contentBounds); + layer->updateCompositorResources(0, updater); + EXPECT_FLOAT_RECT_EQ(FloatRect(layerBounds), layer->updateRect()); + + // Partial re-paint should also be represented by the updateRect in layer space, not content space. + IntRect partialDamage(30, 100, 10, 10); + layer->invalidateRect(partialDamage); + layer->prepareToUpdate(contentBounds); + layer->updateCompositorResources(0, updater); + EXPECT_FLOAT_RECT_EQ(FloatRect(45, 80, 15, 8), layer->updateRect()); +} + +TEST(TiledLayerChromiumTest, skipsDrawGetsReset) +{ + // Initialize without threading support. + WebKit::WebCompositor::initialize(0); + FakeCCLayerTreeHostClient fakeCCLayerTreeHostClient; + RefPtr<CCLayerTreeHost> ccLayerTreeHost = CCLayerTreeHost::create(&fakeCCLayerTreeHostClient, CCSettings()); + + // Create two 300 x 300 tiled layers. + IntSize contentBounds(300, 300); + IntRect contentRect(IntPoint::zero(), contentBounds); + + RefPtr<FakeTiledLayerChromium> rootLayer = adoptRef(new FakeTiledLayerChromium(ccLayerTreeHost->contentsTextureManager())); + RefPtr<FakeTiledLayerChromium> childLayer = adoptRef(new FakeTiledLayerChromium(ccLayerTreeHost->contentsTextureManager())); + rootLayer->addChild(childLayer); + + rootLayer->setBounds(contentBounds); + rootLayer->setPosition(FloatPoint(150, 150)); + childLayer->setBounds(contentBounds); + childLayer->setPosition(FloatPoint(150, 150)); + rootLayer->invalidateRect(contentRect); + childLayer->invalidateRect(contentRect); + + // We have enough memory for only one of the two layers. + int memoryLimit = 4 * 300 * 300; // 4 bytes per pixel. + + FakeTextureAllocator textureAllocator; + CCTextureUpdater updater(&textureAllocator); + + ccLayerTreeHost->setRootLayer(rootLayer); + ccLayerTreeHost->setViewportSize(IntSize(300, 300)); + ccLayerTreeHost->contentsTextureManager()->setMaxMemoryLimitBytes(memoryLimit); + ccLayerTreeHost->updateLayers(); + ccLayerTreeHost->updateCompositorResources(ccLayerTreeHost->context(), updater); + + // We'll skip the root layer. + EXPECT_TRUE(rootLayer->skipsDraw()); + EXPECT_FALSE(childLayer->skipsDraw()); + + ccLayerTreeHost->commitComplete(); + + // Remove the child layer. + rootLayer->removeAllChildren(); + + // Need to set the max limit again as it gets overwritten by updateLayers(). + ccLayerTreeHost->contentsTextureManager()->setMaxMemoryLimitBytes(memoryLimit); + ccLayerTreeHost->updateLayers(); + EXPECT_FALSE(rootLayer->skipsDraw()); + + ccLayerTreeHost->setRootLayer(0); + ccLayerTreeHost.clear(); + WebKit::WebCompositor::shutdown(); +} + +TEST(TiledLayerChromiumTest, layerAddsSelfToOccludedRegion) +{ + OwnPtr<TextureManager> textureManager = TextureManager::create(4*1024*1024, 2*1024*1024, 1024); + RefPtr<FakeTiledLayerChromium> layer = adoptRef(new FakeTiledLayerChromium(textureManager.get())); + + // The tile size is 100x100, so this invalidates and then paints two tiles in various ways. + + Region occluded; + IntRect contentBounds = IntRect(0, 0, 100, 200); + IntRect visibleBounds = IntRect(0, 0, 100, 150); + + layer->setBounds(contentBounds.size()); + layer->setVisibleLayerRect(visibleBounds); + layer->setDrawOpacity(1); + + // The screenSpaceTransform is verified in CCLayerTreeHostCommonTests + TransformationMatrix screenSpaceTransform; + layer->setScreenSpaceTransform(screenSpaceTransform); + + // If the layer is opaque then the occluded region should be the whole layer's visible region. + layer->setOpaque(true); + layer->invalidateRect(contentBounds); + layer->prepareToUpdate(contentBounds); + + occluded = Region(); + layer->addSelfToOccludedScreenSpace(occluded); + EXPECT_EQ_RECT(visibleBounds, occluded.bounds()); + EXPECT_EQ(1u, occluded.rects().size()); + + // If the layer is not opaque then the occluded region should be empty. + layer->setOpaque(false); + layer->invalidateRect(contentBounds); + layer->prepareToUpdate(contentBounds); + + occluded = Region(); + layer->addSelfToOccludedScreenSpace(occluded); + EXPECT_EQ_RECT(IntRect(), occluded.bounds()); + EXPECT_EQ(1u, occluded.rects().size()); + + // If the layer paints opaque content, then the occluded region should match the visible opaque content. + IntRect opaquePaintRect = IntRect(10, 10, 90, 190); + layer->fakeLayerTextureUpdater()->setOpaquePaintRect(opaquePaintRect); + layer->invalidateRect(contentBounds); + layer->prepareToUpdate(contentBounds); + + occluded = Region(); + layer->addSelfToOccludedScreenSpace(occluded); + EXPECT_EQ_RECT(intersection(opaquePaintRect, visibleBounds), occluded.bounds()); + EXPECT_EQ(1u, occluded.rects().size()); + + // If we paint again without invalidating, the same stuff should be occluded. + layer->fakeLayerTextureUpdater()->setOpaquePaintRect(IntRect()); + layer->prepareToUpdate(contentBounds); + + occluded = Region(); + layer->addSelfToOccludedScreenSpace(occluded); + EXPECT_EQ_RECT(intersection(opaquePaintRect, visibleBounds), occluded.bounds()); + EXPECT_EQ(1u, occluded.rects().size()); + + // If the layer is transformed then the resulting occluded area needs to be transformed to its target space. + TransformationMatrix transform; + transform.translate(contentBounds.width() / 2.0, contentBounds.height() / 2.0); + transform.rotate(90); + transform.translate(-contentBounds.width() / 2.0, -contentBounds.height() / 2.0); + transform.translate(10, 10); + screenSpaceTransform.translate(contentBounds.width() / 2.0, contentBounds.height() / 2.0); + screenSpaceTransform *= transform; + screenSpaceTransform.translate(-contentBounds.width() / 2.0, -contentBounds.height() / 2.0); + layer->setScreenSpaceTransform(screenSpaceTransform); + layer->prepareToUpdate(contentBounds); + + occluded = Region(); + layer->addSelfToOccludedScreenSpace(occluded); + EXPECT_EQ_RECT(screenSpaceTransform.mapRect(intersection(opaquePaintRect, visibleBounds)), occluded.bounds()); + EXPECT_EQ(1u, occluded.rects().size()); + + // But a non-axis-aligned transform does not get considered for occlusion. + transform.translate(contentBounds.width() / 2.0, contentBounds.height() / 2.0); + transform.rotate(5); + transform.translate(-contentBounds.width() / 2.0, -contentBounds.height() / 2.0); + screenSpaceTransform.translate(contentBounds.width() / 2.0, contentBounds.height() / 2.0); + screenSpaceTransform *= transform; + screenSpaceTransform.translate(-contentBounds.width() / 2.0, -contentBounds.height() / 2.0); + layer->setScreenSpaceTransform(screenSpaceTransform); + layer->prepareToUpdate(contentBounds); + + occluded = Region(); + layer->addSelfToOccludedScreenSpace(occluded); + // FIXME: If we find an opaque rect contained in the rotated non-axis-aligned rect, then + // this won't be an empty result. + EXPECT_EQ_RECT(IntRect(), occluded.bounds()); + EXPECT_EQ(0u, occluded.rects().size()); +} + } // namespace |