summaryrefslogtreecommitdiff
path: root/Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@nokia.com>2012-02-03 09:55:33 +0100
committerSimon Hausmann <simon.hausmann@nokia.com>2012-02-03 09:55:33 +0100
commitcd44dc59cdfc39534aef4d417e9f3c412e3be139 (patch)
tree8d89889ba95ed6ec9322e733846cc9cce9d7dff1 /Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp
parentd11f84f5b5cdc0d92a08af01b13472fdd5f9acb9 (diff)
downloadqtwebkit-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.cpp311
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