Diff
Modified: trunk/Source/WebCore/ChangeLog (112048 => 112049)
--- trunk/Source/WebCore/ChangeLog 2012-03-26 05:47:21 UTC (rev 112048)
+++ trunk/Source/WebCore/ChangeLog 2012-03-26 06:02:56 UTC (rev 112049)
@@ -1,3 +1,36 @@
+2012-03-25 Dana Jansens <[email protected]>
+
+ [chromium] Layers with animating transforms should prepaint even if they are not visible yet
+ https://bugs.webkit.org/show_bug.cgi?id=82117
+
+ Reviewed by Adrienne Walker.
+
+ For animating transforms, instead of early-outing when the layer's
+ visible rect is empty, let it prepaint regardless.
+
+ For now, we just only paint the outermost tiles, and only for small
+ layers, with at most 9 tiles.
+
+ This changes the behaviour of ContentLayerChromium's
+ idlePaintContentsIfDirty() so I've guarded the behaviour of the two
+ prepainting functions that it calls to ensure the old behaviour holds
+ without animations, and the new behaviour works with them.
+
+ Unit test: TiledLayerChromiumTest.idlePaintZeroSizedLayer
+ TiledLayerChromiumTest.idlePaintZeroSizedAnimatingLayer
+ TiledLayerChromiumTest.idlePaintNonVisibleLayers
+ TiledLayerChromiumTest.idlePaintNonVisibleAnimatingLayers
+
+ * platform/graphics/chromium/ContentLayerChromium.cpp:
+ (WebCore::ContentLayerChromium::idlePaintContentsIfDirty):
+ * platform/graphics/chromium/TiledLayerChromium.cpp:
+ (WebCore::TiledLayerChromium::prepareToUpdateIdle):
+ (WebCore::TiledLayerChromium::needsIdlePaint):
+ (WebCore::TiledLayerChromium::idlePaintRect):
+ * platform/graphics/chromium/TiledLayerChromium.h:
+ (WebCore::TiledLayerChromium::numPaintedTiles):
+ (TiledLayerChromium):
+
2012-03-25 Antti Koivisto <[email protected]>
Don't use CSSRuleList for child rule ownership
Modified: trunk/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp (112048 => 112049)
--- trunk/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp 2012-03-26 05:47:21 UTC (rev 112048)
+++ trunk/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp 2012-03-26 06:02:56 UTC (rev 112049)
@@ -114,10 +114,7 @@
if (!drawsContent())
return;
- const IntRect& layerRect = visibleLayerRect();
- if (layerRect.isEmpty())
- return;
-
+ const IntRect layerRect = visibleLayerRect();
prepareToUpdateIdle(layerRect, occlusion);
if (needsIdlePaint(layerRect))
setNeedsCommit();
Modified: trunk/Source/WebCore/platform/graphics/chromium/TiledLayerChromium.cpp (112048 => 112049)
--- trunk/Source/WebCore/platform/graphics/chromium/TiledLayerChromium.cpp 2012-03-26 05:47:21 UTC (rev 112048)
+++ trunk/Source/WebCore/platform/graphics/chromium/TiledLayerChromium.cpp 2012-03-26 06:02:56 UTC (rev 112049)
@@ -628,25 +628,46 @@
updateBounds();
- if (m_tiler->isEmpty())
+ if (!m_tiler->numTiles())
return;
- // Protect any textures in the pre-paint area so we don't end up just
- // reclaiming them below.
IntRect idlePaintLayerRect = idlePaintRect(layerRect);
+ if (idlePaintLayerRect.isEmpty())
+ return;
+
+ // Protect any textures in the pre-paint area, as we would steal them from other layers
+ // over time anyhow. This ensures we don't lose tiles in the first rounds of idle painting
+ // that we have already painted.
protectTileTextures(idlePaintLayerRect);
+ int prepaintLeft, prepaintTop, prepaintRight, prepaintBottom;
+ m_tiler->layerRectToTileIndices(idlePaintLayerRect, prepaintLeft, prepaintTop, prepaintRight, prepaintBottom);
+
+ // If the layer is not visible, we have nothing to expand from, so instead we prepaint the outer-most set of tiles.
+ if (layerRect.isEmpty()) {
+ prepareToUpdateTiles(true, prepaintLeft, prepaintTop, prepaintRight, prepaintTop, 0);
+ if (!m_paintRect.isEmpty() || m_skipsIdlePaint)
+ return;
+ prepareToUpdateTiles(true, prepaintLeft, prepaintBottom, prepaintRight, prepaintBottom, 0);
+ if (!m_paintRect.isEmpty() || m_skipsIdlePaint)
+ return;
+ prepareToUpdateTiles(true, prepaintLeft, prepaintTop, prepaintLeft, prepaintBottom, 0);
+ if (!m_paintRect.isEmpty() || m_skipsIdlePaint)
+ return;
+ prepareToUpdateTiles(true, prepaintRight, prepaintTop, prepaintRight, prepaintBottom, 0);
+
+ return;
+ }
+
int left, top, right, bottom;
m_tiler->layerRectToTileIndices(layerRect, left, top, right, bottom);
- // Prepaint anything that was occluded but inside the layer's visible region.
+ // Otherwise, prepaint anything that was occluded but inside the layer's visible region.
prepareToUpdateTiles(true, left, top, right, bottom, 0);
if (!m_paintRect.isEmpty() || m_skipsIdlePaint)
return;
- // Expand outwards until we find a dirty row or column to update.
- int prepaintLeft, prepaintTop, prepaintRight, prepaintBottom;
- m_tiler->layerRectToTileIndices(idlePaintLayerRect, prepaintLeft, prepaintTop, prepaintRight, prepaintBottom);
+ // Then expand outwards from the visible area until we find a dirty row or column to update.
while (!m_skipsIdlePaint && (left > prepaintLeft || top > prepaintTop || right < prepaintRight || bottom < prepaintBottom)) {
if (bottom < prepaintBottom) {
++bottom;
@@ -680,12 +701,20 @@
if (m_skipsIdlePaint)
return false;
+ if (!m_tiler->numTiles())
+ return false;
+
IntRect idlePaintLayerRect = idlePaintRect(layerRect);
+ if (idlePaintLayerRect.isEmpty())
+ return false;
int left, top, right, bottom;
m_tiler->layerRectToTileIndices(idlePaintLayerRect, left, top, right, bottom);
for (int j = top; j <= bottom; ++j) {
for (int i = left; i <= right; ++i) {
+ // If the layerRect is empty, then we are painting the outer-most set of tiles only.
+ if (layerRect.isEmpty() && i != left && i != right && j != top && j != bottom)
+ continue;
if (m_requestedUpdateTilesRect.contains(IntPoint(i, j)))
continue;
UpdatableTile* tile = tileAt(i, j);
@@ -698,6 +727,15 @@
IntRect TiledLayerChromium::idlePaintRect(const IntRect& visibleLayerRect)
{
+ // For layers that are animating transforms but not visible at all, we don't know what part
+ // of them is going to become visible. For small layers we return the entire layer, for larger
+ // ones we avoid prepainting the layer at all.
+ if (visibleLayerRect.isEmpty()) {
+ if ((drawTransformIsAnimating() || screenSpaceTransformIsAnimating()) && m_tiler->numTiles() <= 9)
+ return IntRect(IntPoint(), contentBounds());
+ return IntRect();
+ }
+
IntRect prepaintRect = visibleLayerRect;
// FIXME: This can be made a lot larger if we can:
// - reserve memory at a lower priority than for visible content
Modified: trunk/Source/WebCore/platform/graphics/chromium/TiledLayerChromium.h (112048 => 112049)
--- trunk/Source/WebCore/platform/graphics/chromium/TiledLayerChromium.h 2012-03-26 05:47:21 UTC (rev 112048)
+++ trunk/Source/WebCore/platform/graphics/chromium/TiledLayerChromium.h 2012-03-26 06:02:56 UTC (rev 112049)
@@ -77,6 +77,7 @@
void setTextureFormat(GC3Denum textureFormat) { m_textureFormat = textureFormat; }
void setBorderTexelOption(CCLayerTilingData::BorderTexelOption);
void setSampledTexelFormat(LayerTextureUpdater::SampledTexelFormat sampledTexelFormat) { m_sampledTexelFormat = sampledTexelFormat; }
+ size_t numPaintedTiles() { return m_tiler->tiles().size(); }
virtual LayerTextureUpdater* textureUpdater() const = 0;
virtual void createTextureUpdaterIfNeeded() = 0;
@@ -96,6 +97,8 @@
// After preparing an update, returns true if more pre-painting is needed.
bool needsIdlePaint(const IntRect& layerRect);
+ IntRect idlePaintRect(const IntRect& visibleLayerRect);
+
bool skipsDraw() const { return m_skipsDraw; }
virtual void protectVisibleTileTextures();
@@ -112,7 +115,6 @@
bool tileNeedsBufferedUpdate(UpdatableTile*);
void prepareToUpdateTiles(bool idle, int left, int top, int right, int bottom, const CCOcclusionTracker*);
- IntRect idlePaintRect(const IntRect& visibleLayerRect);
UpdatableTile* tileAt(int, int) const;
UpdatableTile* createTile(int, int);
Modified: trunk/Source/WebKit/chromium/ChangeLog (112048 => 112049)
--- trunk/Source/WebKit/chromium/ChangeLog 2012-03-26 05:47:21 UTC (rev 112048)
+++ trunk/Source/WebKit/chromium/ChangeLog 2012-03-26 06:02:56 UTC (rev 112049)
@@ -1,3 +1,19 @@
+2012-03-25 Dana Jansens <[email protected]>
+
+ [chromium] Layers with animating transforms should prepaint even if they are not visible yet
+ https://bugs.webkit.org/show_bug.cgi?id=82117
+
+ Reviewed by Adrienne Walker.
+
+ * tests/TiledLayerChromiumTest.cpp:
+ (WTF::FakeTiledLayerChromium::FakeTiledLayerChromium):
+ (WTF::FakeTiledLayerChromium::tileSize):
+ (FakeTiledLayerChromium):
+ (WTF::TEST):
+ (WTF):
+ (WTF::idlePaintRepeat):
+ (WTF::testHaveOuterTiles):
+
2012-03-24 Nat Duca <[email protected]>
[chromium] Instrument gesture animations with async traces
Modified: trunk/Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp (112048 => 112049)
--- trunk/Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp 2012-03-26 05:47:21 UTC (rev 112048)
+++ trunk/Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp 2012-03-26 06:02:56 UTC (rev 112049)
@@ -26,6 +26,7 @@
#include "TiledLayerChromium.h"
+#include "CCAnimationTestCommon.h"
#include "CCLayerTreeTestCommon.h"
#include "FakeCCLayerTreeHostClient.h"
#include "LayerTextureUpdater.h"
@@ -38,6 +39,7 @@
#include <gtest/gtest.h>
using namespace WebCore;
+using namespace WebKitTests;
using namespace WTF;
#define EXPECT_EQ_RECT(a, b) \
@@ -160,38 +162,23 @@
, m_fakeTextureUpdater(adoptRef(new FakeLayerTextureUpdater))
, m_textureManager(textureManager)
{
- setTileSize(IntSize(100, 100));
+ setTileSize(tileSize());
setTextureFormat(GraphicsContext3D::RGBA);
setBorderTexelOption(CCLayerTilingData::NoBorderTexels);
setIsDrawable(true); // So that we don't get false positives if any of these tests expect to return false from drawsContent() for other reasons.
}
virtual ~FakeTiledLayerChromium() { }
- void invalidateRect(const IntRect& rect)
- {
- TiledLayerChromium::invalidateRect(rect);
- }
+ static IntSize tileSize() { return IntSize(100, 100); }
- void prepareToUpdate(const IntRect& rect, const CCOcclusionTracker* occlusion)
- {
- TiledLayerChromium::prepareToUpdate(rect, occlusion);
- }
+ using TiledLayerChromium::invalidateRect;
+ using TiledLayerChromium::prepareToUpdate;
+ using TiledLayerChromium::prepareToUpdateIdle;
+ using TiledLayerChromium::needsIdlePaint;
+ using TiledLayerChromium::skipsDraw;
+ using TiledLayerChromium::numPaintedTiles;
+ using TiledLayerChromium::idlePaintRect;
- void prepareToUpdateIdle(const IntRect& rect, const CCOcclusionTracker* occlusion)
- {
- TiledLayerChromium::prepareToUpdateIdle(rect, occlusion);
- }
-
- bool needsIdlePaint(const IntRect& rect)
- {
- return TiledLayerChromium::needsIdlePaint(rect);
- }
-
- bool skipsDraw() const
- {
- return TiledLayerChromium::skipsDraw();
- }
-
virtual void setNeedsDisplayRect(const FloatRect& rect)
{
m_lastNeedsDisplayRect = rect;
@@ -687,6 +674,211 @@
layer->pushPropertiesTo(layerImpl.get());
}
+TEST(TiledLayerChromiumTest, idlePaintZeroSizedLayer)
+{
+ OwnPtr<TextureManager> textureManager = TextureManager::create(20000, 10000, 1024);
+ RefPtr<FakeTiledLayerChromium> layer = adoptRef(new FakeTiledLayerChromium(textureManager.get()));
+ DebugScopedSetImplThread implThread;
+ OwnPtr<FakeCCTiledLayerImpl> layerImpl(adoptPtr(new FakeCCTiledLayerImpl(0)));
+
+ FakeTextureAllocator textureAllocator;
+ CCTextureUpdater updater(&textureAllocator);
+
+ // The layer's bounds are empty.
+ IntRect contentRect;
+
+ layer->setBounds(contentRect.size());
+ layer->setVisibleLayerRect(contentRect);
+ layer->invalidateRect(contentRect);
+ layer->prepareToUpdate(contentRect, 0);
+
+ // Empty layers don't have tiles.
+ EXPECT_EQ(0u, layer->numPaintedTiles());
+
+ // Empty layers don't need prepaint.
+ EXPECT_FALSE(layer->needsIdlePaint(contentRect));
+
+ layer->updateCompositorResources(0, updater);
+ layer->pushPropertiesTo(layerImpl.get());
+
+ // Empty layers don't have tiles.
+ EXPECT_FALSE(layerImpl->hasTileAt(0, 0));
+
+ // Non-visible layers don't idle paint.
+ layer->prepareToUpdateIdle(contentRect, 0);
+
+ // Empty layers don't have tiles.
+ EXPECT_EQ(0u, layer->numPaintedTiles());
+
+ layer->updateCompositorResources(0, updater);
+ layer->pushPropertiesTo(layerImpl.get());
+
+ // Empty layers don't have tiles.
+ EXPECT_FALSE(layerImpl->hasTileAt(0, 0));
+}
+
+TEST(TiledLayerChromiumTest, idlePaintZeroSizedAnimatingLayer)
+{
+ OwnPtr<TextureManager> textureManager = TextureManager::create(20000, 10000, 1024);
+ RefPtr<FakeTiledLayerChromium> layer = adoptRef(new FakeTiledLayerChromium(textureManager.get()));
+ DebugScopedSetImplThread implThread;
+ OwnPtr<FakeCCTiledLayerImpl> layerImpl(adoptPtr(new FakeCCTiledLayerImpl(0)));
+
+ FakeTextureAllocator textureAllocator;
+ CCTextureUpdater updater(&textureAllocator);
+
+ // Pretend the layer is animating.
+ layer->setDrawTransformIsAnimating(true);
+
+ // The layer's bounds are empty.
+ IntRect contentRect;
+
+ layer->setBounds(contentRect.size());
+ layer->setVisibleLayerRect(contentRect);
+ layer->invalidateRect(contentRect);
+ layer->prepareToUpdate(contentRect, 0);
+
+ // Empty layers don't have tiles.
+ EXPECT_EQ(0u, layer->numPaintedTiles());
+
+ // Empty layers don't need prepaint.
+ EXPECT_FALSE(layer->needsIdlePaint(contentRect));
+
+ layer->updateCompositorResources(0, updater);
+ layer->pushPropertiesTo(layerImpl.get());
+
+ // Empty layers don't have tiles.
+ EXPECT_FALSE(layerImpl->hasTileAt(0, 0));
+
+ // Non-visible layers don't idle paint.
+ layer->prepareToUpdateIdle(contentRect, 0);
+
+ // Empty layers don't have tiles.
+ EXPECT_EQ(0u, layer->numPaintedTiles());
+
+ layer->updateCompositorResources(0, updater);
+ layer->pushPropertiesTo(layerImpl.get());
+
+ // Empty layers don't have tiles.
+ EXPECT_FALSE(layerImpl->hasTileAt(0, 0));
+}
+
+TEST(TiledLayerChromiumTest, idlePaintNonVisibleLayers)
+{
+ IntSize contentBounds(100, 100);
+ IntRect contentRect(IntPoint::zero(), contentBounds);
+
+ OwnPtr<TextureManager> textureManager = TextureManager::create(20000, 10000, 1024);
+ RefPtr<FakeTiledLayerChromium> layer = adoptRef(new FakeTiledLayerChromium(textureManager.get()));
+ DebugScopedSetImplThread implThread;
+ OwnPtr<FakeCCTiledLayerImpl> layerImpl(adoptPtr(new FakeCCTiledLayerImpl(0)));
+
+ FakeTextureAllocator textureAllocator;
+ CCTextureUpdater updater(&textureAllocator);
+
+ // Invalidate the layer but make none of it visible, so nothing paints.
+ IntRect visibleRect;
+
+ layer->setBounds(contentBounds);
+ layer->setVisibleLayerRect(visibleRect);
+ layer->invalidateRect(contentRect);
+ layer->prepareToUpdate(visibleRect, 0);
+
+ // Non-visible layers don't need idle paint.
+ EXPECT_FALSE(layer->needsIdlePaint(visibleRect));
+
+ layer->updateCompositorResources(0, updater);
+ layer->pushPropertiesTo(layerImpl.get());
+
+ // We should not have any tiles pushed since the layer is not visible.
+ EXPECT_FALSE(layerImpl->hasTileAt(0, 0));
+
+ // Non-visible layers don't idle paint.
+ layer->prepareToUpdateIdle(visibleRect, 0);
+
+ layer->updateCompositorResources(0, updater);
+ layer->pushPropertiesTo(layerImpl.get());
+
+ // We should not have any tiles pushed since the layer is not visible.
+ EXPECT_FALSE(layerImpl->hasTileAt(0, 0));
+}
+
+static void idlePaintRepeat(int repeatTimes, FakeTiledLayerChromium* layer, FakeCCTiledLayerImpl* layerImpl, CCTextureUpdater& updater, const IntRect& visibleRect)
+{
+ for (int i = 0; i < repeatTimes; ++i) {
+ layer->prepareToUpdate(visibleRect, 0);
+ layer->prepareToUpdateIdle(visibleRect, 0);
+ layer->updateCompositorResources(0, updater);
+ layer->pushPropertiesTo(layerImpl);
+ }
+}
+
+static void testHaveOuterTiles(FakeCCTiledLayerImpl* layerImpl, int width, int height, int have)
+{
+ for (int i = 0; i < width; ++i) {
+ for (int j = 0; j < height; ++j) {
+ bool hasTile = i < have || j < have || i >= width - have || j >= height - have;
+ EXPECT_EQ(hasTile, layerImpl->hasTileAt(i, j));
+ }
+ }
+}
+
+TEST(TiledLayerChromiumTest, idlePaintNonVisibleAnimatingLayers)
+{
+ OwnPtr<TextureManager> textureManager = TextureManager::create(8000*8000*8, 8000*8000*4, 1024);
+ DebugScopedSetImplThread implThread;
+
+ FakeTextureAllocator textureAllocator;
+ CCTextureUpdater updater(&textureAllocator);
+
+ int tileWidth = FakeTiledLayerChromium::tileSize().width();
+ int tileHeight = FakeTiledLayerChromium::tileSize().height();
+ int width[] = { 1, 2, 3, 4, 9, 10, 0 };
+ int height[] = { 1, 2, 3, 4, 9, 10, 0 };
+
+ for (int j = 0; height[j]; ++j) {
+ for (int i = 0; width[i]; ++i) {
+ RefPtr<FakeTiledLayerChromium> layer = adoptRef(new FakeTiledLayerChromium(textureManager.get()));
+ OwnPtr<FakeCCTiledLayerImpl> layerImpl(adoptPtr(new FakeCCTiledLayerImpl(0)));
+
+ // Pretend the layer is animating.
+ layer->setDrawTransformIsAnimating(true);
+
+ IntSize contentBounds(width[i] * tileWidth, height[j] * tileHeight);
+ IntRect contentRect(IntPoint::zero(), contentBounds);
+ IntRect visibleRect;
+
+ layer->setBounds(contentBounds);
+ layer->setVisibleLayerRect(visibleRect);
+ layer->invalidateRect(contentRect);
+
+ // If idlePaintRect gives back a non-empty result then we should paint it. Otherwise,
+ // we shoud paint nothing.
+ bool shouldPrepaint = !layer->idlePaintRect(visibleRect).isEmpty();
+
+ // This paints the layer but there's nothing visible so it's a no-op.
+ layer->prepareToUpdate(visibleRect, 0);
+ layer->updateCompositorResources(0, updater);
+ layer->pushPropertiesTo(layerImpl.get());
+
+ // We should not have any tiles pushed yet since the layer is not visible and we've not prepainted.
+ testHaveOuterTiles(layerImpl.get(), width[i], height[j], 0);
+
+ // Normally we don't allow non-visible layers to pre-paint, but if they are animating then we should.
+ EXPECT_EQ(shouldPrepaint, layer->needsIdlePaint(visibleRect));
+
+ // If the layer is to be prepainted at all, then after four updates we should have the outer row/columns painted.
+ idlePaintRepeat(4, layer.get(), layerImpl.get(), updater, visibleRect);
+ testHaveOuterTiles(layerImpl.get(), width[i], height[j], shouldPrepaint ? 1 : 0);
+
+ // We don't currently idle paint past the outermost tiles.
+ EXPECT_FALSE(layer->needsIdlePaint(visibleRect));
+ idlePaintRepeat(4, layer.get(), layerImpl.get(), updater, visibleRect);
+ testHaveOuterTiles(layerImpl.get(), width[i], height[j], shouldPrepaint ? 1 : 0);
+ }
+ }
+}
+
TEST(TiledLayerChromiumTest, invalidateFromPrepare)
{
OwnPtr<TextureManager> textureManager = TextureManager::create(4*1024*1024, 2*1024*1024, 1024);