Title: [125498] trunk/Source
Revision
125498
Author
[email protected]
Date
2012-08-13 19:14:16 -0700 (Mon, 13 Aug 2012)

Log Message

[chromium] Paint animated layers immediately to avoid animation hiccups.
https://bugs.webkit.org/show_bug.cgi?id=93028

Patch by Eric Penner <[email protected]> on 2012-08-13
Reviewed by Adrienne Walker.

Source/WebCore:

This is a technique used on Android, which is very prone
to hiccups in animations. Paint the entire layer if it is
of reasonable size such that there is no hiccups when the
animation reaches unpainted content. The reasonable size
is choosen for page-transitions specifically, as this was
the problem case (animations would just jump to the end).

Since we already have a special case this just modifies it
and replaces the unit test with a new one. This can be
improved/simplified further when distances/directions are
available for the animated layers.

Replaced one test.
Fixed bugs in and improved idlePaintNonVisibleLayers test.

* platform/graphics/chromium/TiledLayerChromium.cpp:
(UpdatableTile):
(WebCore::UpdatableTile::resetUpdateState):
(WebCore::UpdatableTile::markForUpdate):
(WebCore::UpdatableTile::UpdatableTile):
(WebCore::TiledLayerChromium::TiledLayerChromium):
(WebCore::TiledLayerChromium::pushPropertiesTo):
(WebCore):
(WebCore::TiledLayerChromium::updateTiles):
(WebCore::TiledLayerChromium::markOcclusionsAndRequestTextures):
(WebCore::TiledLayerChromium::haveTexturesForTiles):
(WebCore::TiledLayerChromium::markTilesForUpdate):
(WebCore::TiledLayerChromium::updateTileTextures):
(WebCore::TiledLayerChromium::setTexturePrioritiesInRect):
(WebCore::TiledLayerChromium::resetUpdateState):
(WebCore::TiledLayerChromium::updateContentRect):
(WebCore::TiledLayerChromium::needsIdlePaint):
(WebCore::TiledLayerChromium::idlePaintRect):
* platform/graphics/chromium/TiledLayerChromium.h:
(TiledLayerChromium):
* platform/graphics/chromium/cc/CCLayerTilingData.cpp:
(WebCore::CCLayerTilingData::contentRectToTileIndices):
* platform/graphics/chromium/cc/CCPriorityCalculator.h:
(WebCore::CCPriorityCalculator::maxPriority):

Source/WebKit/chromium:

Replaced one test. Test painting full animated layer.

* tests/TiledLayerChromiumTest.cpp:

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (125497 => 125498)


--- trunk/Source/WebCore/ChangeLog	2012-08-14 02:10:43 UTC (rev 125497)
+++ trunk/Source/WebCore/ChangeLog	2012-08-14 02:14:16 UTC (rev 125498)
@@ -1,3 +1,50 @@
+2012-08-13  Eric Penner  <[email protected]>
+
+        [chromium] Paint animated layers immediately to avoid animation hiccups.
+        https://bugs.webkit.org/show_bug.cgi?id=93028
+
+        Reviewed by Adrienne Walker.
+
+        This is a technique used on Android, which is very prone
+        to hiccups in animations. Paint the entire layer if it is
+        of reasonable size such that there is no hiccups when the
+        animation reaches unpainted content. The reasonable size
+        is choosen for page-transitions specifically, as this was
+        the problem case (animations would just jump to the end).
+
+        Since we already have a special case this just modifies it
+        and replaces the unit test with a new one. This can be
+        improved/simplified further when distances/directions are
+        available for the animated layers.
+
+        Replaced one test.
+        Fixed bugs in and improved idlePaintNonVisibleLayers test.
+
+        * platform/graphics/chromium/TiledLayerChromium.cpp:
+        (UpdatableTile):
+        (WebCore::UpdatableTile::resetUpdateState):
+        (WebCore::UpdatableTile::markForUpdate):
+        (WebCore::UpdatableTile::UpdatableTile):
+        (WebCore::TiledLayerChromium::TiledLayerChromium):
+        (WebCore::TiledLayerChromium::pushPropertiesTo):
+        (WebCore):
+        (WebCore::TiledLayerChromium::updateTiles):
+        (WebCore::TiledLayerChromium::markOcclusionsAndRequestTextures):
+        (WebCore::TiledLayerChromium::haveTexturesForTiles):
+        (WebCore::TiledLayerChromium::markTilesForUpdate):
+        (WebCore::TiledLayerChromium::updateTileTextures):
+        (WebCore::TiledLayerChromium::setTexturePrioritiesInRect):
+        (WebCore::TiledLayerChromium::resetUpdateState):
+        (WebCore::TiledLayerChromium::updateContentRect):
+        (WebCore::TiledLayerChromium::needsIdlePaint):
+        (WebCore::TiledLayerChromium::idlePaintRect):
+        * platform/graphics/chromium/TiledLayerChromium.h:
+        (TiledLayerChromium):
+        * platform/graphics/chromium/cc/CCLayerTilingData.cpp:
+        (WebCore::CCLayerTilingData::contentRectToTileIndices):
+        * platform/graphics/chromium/cc/CCPriorityCalculator.h:
+        (WebCore::CCPriorityCalculator::maxPriority):
+
 2012-08-13  Kentaro Hara  <[email protected]>
 
         Unreviewed. Simple refactoring that I forgot to apply in r125495.

Modified: trunk/Source/WebCore/platform/graphics/chromium/TiledLayerChromium.cpp (125497 => 125498)


--- trunk/Source/WebCore/platform/graphics/chromium/TiledLayerChromium.cpp	2012-08-14 02:10:43 UTC (rev 125497)
+++ trunk/Source/WebCore/platform/graphics/chromium/TiledLayerChromium.cpp	2012-08-14 02:14:16 UTC (rev 125498)
@@ -402,7 +402,7 @@
             // FIXME: This should not ever be null.
             if (!tile)
                 continue;
-            ASSERT(!tile->occluded); // Did resetUpdateState get skipped? Are we doing more than one occluded pass?
+            ASSERT(!tile->occluded); // Did resetUpdateState get skipped? Are we doing more than one occlusion pass?
             IntRect visibleTileRect = intersection(m_tiler->tileBounds(i, j), visibleContentRect());
             if (occlusion && occlusion->occluded(this, visibleTileRect)) {
                 tile->occluded = true;
@@ -560,31 +560,77 @@
     setTexturePrioritiesInRect(priorityCalc, visibleContentRect());
 }
 
+namespace {
+// This picks a small animated layer to be anything less than one viewport. This
+// is specifically for page transitions which are viewport-sized layers. The extra
+// 64 pixels is due to these layers being slightly larger than the viewport in some cases.
+bool isSmallAnimatedLayer(TiledLayerChromium* layer)
+{
+    if (!layer->drawTransformIsAnimating() && !layer->screenSpaceTransformIsAnimating())
+        return false;
+    IntSize viewportSize = layer->layerTreeHost() ? layer->layerTreeHost()->deviceViewportSize() : IntSize();
+    IntRect contentRect(IntPoint::zero(), layer->contentBounds());
+    return contentRect.width() <= viewportSize.width() + 64
+        && contentRect.height() <= viewportSize.height() + 64;
+}
+
+// FIXME: Remove this and make this based on distance once distance can be calculated
+// for offscreen layers. For now, prioritize all small animated layers after 512
+// pixels of pre-painting.
+void setPriorityForTexture(const CCPriorityCalculator& priorityCalc,
+                           const IntRect& visibleRect,
+                           const IntRect& tileRect,
+                           bool drawsToRoot,
+                           bool isSmallAnimatedLayer,
+                           CCPrioritizedTexture* texture)
+{
+    int priority = CCPriorityCalculator::lowestPriority();
+    if (!visibleRect.isEmpty())
+        priority = priorityCalc.priorityFromDistance(visibleRect, tileRect, drawsToRoot);
+    if (isSmallAnimatedLayer)
+        priority = CCPriorityCalculator::maxPriority(priority, priorityCalc.priorityFromDistance(512, drawsToRoot));
+    if (priority != CCPriorityCalculator::lowestPriority())
+        texture->setRequestPriority(priority);
+}
+}
+
 void TiledLayerChromium::setTexturePrioritiesInRect(const CCPriorityCalculator& priorityCalc, const IntRect& visibleContentRect)
 {
     updateBounds();
     resetUpdateState();
 
-    IntRect prepaintRect = idlePaintRect(visibleContentRect);
+    if (m_tiler->hasEmptyBounds())
+        return;
+
     bool drawsToRoot = !renderTarget()->parent();
+    bool smallAnimatedLayer = isSmallAnimatedLayer(this);
 
     // Minimally create the tiles in the desired pre-paint rect.
-    if (!prepaintRect.isEmpty()) {
+    IntRect createTilesRect = idlePaintRect(visibleContentRect);
+    if (!createTilesRect.isEmpty()) {
         int left, top, right, bottom;
-        m_tiler->contentRectToTileIndices(prepaintRect, left, top, right, bottom);
-        for (int j = top; j <= bottom; ++j)
-            for (int i = left; i <= right; ++i)
+        m_tiler->contentRectToTileIndices(createTilesRect, left, top, right, bottom);
+        for (int j = top; j <= bottom; ++j) {
+            for (int i = left; i <= right; ++i) {
                 if (!tileAt(i, j))
                     createTile(i, j);
+            }
+        }
     }
 
+    // Also, minimally create all tiles for small animated layers and also
+    // double-buffer them since we have limited their size to be reasonable.
+    IntRect doubleBufferedRect = visibleContentRect;
+    if (smallAnimatedLayer)
+        doubleBufferedRect = IntRect(IntPoint::zero(), contentBounds());
+
     // Create additional textures for double-buffered updates when needed.
     // These textures must stay alive while the updated textures are incrementally
     // uploaded, swapped atomically via pushProperties, and finally deleted
     // after the commit is complete, after which they can be recycled.
-    if (!visibleContentRect.isEmpty()) {
+    if (!doubleBufferedRect.isEmpty()) {
         int left, top, right, bottom;
-        m_tiler->contentRectToTileIndices(visibleContentRect, left, top, right, bottom);
+        m_tiler->contentRectToTileIndices(doubleBufferedRect, left, top, right, bottom);
         for (int j = top; j <= bottom; ++j) {
             for (int i = left; i <= right; ++i) {
                 UpdatableTile* tile = tileAt(i, j);
@@ -600,9 +646,10 @@
                     continue;
                 }
 
-                tile->dirtyRect = m_tiler->tileRect(tile);
+                IntRect tileRect = m_tiler->tileRect(tile);
+                tile->dirtyRect = tileRect;
                 LayerTextureUpdater::Texture* backBuffer = tile->texture();
-                backBuffer->texture()->setRequestPriority(priorityCalc.priorityFromVisibility(true, drawsToRoot));
+                setPriorityForTexture(priorityCalc, visibleContentRect, tile->dirtyRect, drawsToRoot, smallAnimatedLayer, backBuffer->texture());
                 OwnPtr<CCPrioritizedTexture> frontBuffer = CCPrioritizedTexture::create(backBuffer->texture()->textureManager(),
                                                                                         backBuffer->texture()->size(),
                                                                                         backBuffer->texture()->format());
@@ -613,18 +660,14 @@
         }
     }
 
-    // Now set priorities on all tiles.
+    // Now update priorities on all tiles we have in the layer, no matter where they are.
     for (CCLayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(); iter != m_tiler->tiles().end(); ++iter) {
         UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second.get());
+        // FIXME: This should not ever be null.
+        if (!tile)
+            continue;
         IntRect tileRect = m_tiler->tileRect(tile);
-        // FIXME: This indicates the "small animated layer" case. This special case
-        // can be removed soon with better priorities, but for now paint these layers after
-        // 512 pixels of pre-painting. Later we can just pass an animating flag etc. to the
-        // calculator and it can take care of this special case if we still need it.
-        if (visibleContentRect.isEmpty() && !prepaintRect.isEmpty())
-            tile->managedTexture()->setRequestPriority(priorityCalc.priorityFromDistance(512, drawsToRoot));
-        else if (!visibleContentRect.isEmpty())
-            tile->managedTexture()->setRequestPriority(priorityCalc.priorityFromDistance(visibleContentRect, tileRect, drawsToRoot));
+        setPriorityForTexture(priorityCalc, visibleContentRect, tileRect, drawsToRoot, smallAnimatedLayer, tile->managedTexture());
     }
 }
 
@@ -660,45 +703,45 @@
 
     bool didPaint = false;
 
-    // Visible painting. Only paint visible tiles if the visible rect isn't empty.
-    if (!contentRect.isEmpty()) {
+    // Animation pre-paint. If the layer is small, try to paint it all
+    // immediately whether or not it is occluded, to avoid paint/upload
+    // hiccups while it is animating.
+    if (isSmallAnimatedLayer(this)) {
         int left, top, right, bottom;
-        m_tiler->contentRectToTileIndices(contentRect, left, top, right, bottom);
-        markOcclusionsAndRequestTextures(left, top, right, bottom, occlusion);
-        m_skipsDraw = !updateTiles(left, top, right, bottom, queue, occlusion, stats, didPaint);
-        if (m_skipsDraw)
-            m_tiler->reset();
-        if (m_skipsDraw || didPaint)
+        m_tiler->contentRectToTileIndices(IntRect(IntPoint::zero(), contentBounds()), left, top, right, bottom);
+        updateTiles(left, top, right, bottom, queue, 0, stats, didPaint);
+        if (didPaint)
             return;
+        // This was an attempt to paint the entire layer so if we fail it's okay,
+        // just fallback on painting visible etc. below.
+        m_failedUpdate = false;
     }
 
+    if (contentRect.isEmpty())
+        return;
+
+    // Visible painting. First occlude visible tiles and paint the non-occluded tiles.
+    int left, top, right, bottom;
+    m_tiler->contentRectToTileIndices(contentRect, left, top, right, bottom);
+    markOcclusionsAndRequestTextures(left, top, right, bottom, occlusion);
+    m_skipsDraw = !updateTiles(left, top, right, bottom, queue, occlusion, stats, didPaint);
+    if (m_skipsDraw)
+        m_tiler->reset();
+    if (m_skipsDraw || didPaint)
+        return;
+
     // If we have already painting everything visible. Do some pre-painting while idle.
     IntRect idlePaintContentRect = idlePaintRect(contentRect);
     if (idlePaintContentRect.isEmpty())
         return;
 
+    // Prepaint anything that was occluded but inside the layer's visible region.
+    if (!updateTiles(left, top, right, bottom, queue, 0, stats, didPaint) || didPaint)
+        return;
+
     int prepaintLeft, prepaintTop, prepaintRight, prepaintBottom;
     m_tiler->contentRectToTileIndices(idlePaintContentRect, 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 (contentRect.isEmpty()) {
-        if (!updateTiles(prepaintLeft, prepaintTop, prepaintRight, prepaintTop, queue, 0, stats, didPaint) || didPaint)
-            return;
-        if (!updateTiles(prepaintLeft, prepaintBottom, prepaintRight, prepaintBottom, queue, 0, stats, didPaint) || didPaint)
-            return;
-        if (!updateTiles(prepaintLeft, prepaintTop, prepaintLeft, prepaintBottom, queue, 0, stats, didPaint) || didPaint)
-            return;
-        updateTiles(prepaintRight, prepaintTop, prepaintRight, prepaintBottom, queue, 0, stats, didPaint);
-        return;
-    }
-
-    int left, top, right, bottom;
-    m_tiler->contentRectToTileIndices(contentRect, left, top, right, bottom);
-
-    // Otherwise, prepaint anything that was occluded but inside the layer's visible region.
-    if (!updateTiles(left, top, right, bottom, queue, 0, stats, didPaint) || didPaint)
-        return;
-
     // Then expand outwards from the visible area until we find a dirty row or column to update.
     while (left > prepaintLeft || top > prepaintTop || right < prepaintRight || bottom < prepaintBottom) {
         if (bottom < prepaintBottom) {
@@ -727,12 +770,9 @@
 bool TiledLayerChromium::needsIdlePaint(const IntRect& visibleContentRect)
 {
     // Don't trigger more paints if we failed (as we'll just fail again).
-    if (m_failedUpdate)
+    if (m_failedUpdate || visibleContentRect.isEmpty() || m_tiler->hasEmptyBounds())
         return false;
 
-    if (m_tiler->hasEmptyBounds())
-        return false;
-
     IntRect idlePaintContentRect = idlePaintRect(visibleContentRect);
     if (idlePaintContentRect.isEmpty())
         return false;
@@ -742,9 +782,6 @@
 
     for (int j = top; j <= bottom; ++j) {
         for (int i = left; i <= right; ++i) {
-            // If the visibleContentRect is empty, then we are painting the outer-most set of tiles only.
-            if (visibleContentRect.isEmpty() && i != left && i != right && j != top && j != bottom)
-                continue;
             UpdatableTile* tile = tileAt(i, j);
             ASSERT(tile); // Did setTexturePriorities get skipped?
             if (!tile)
@@ -762,23 +799,16 @@
 
 IntRect TiledLayerChromium::idlePaintRect(const IntRect& visibleContentRect)
 {
-    IntRect contentRect(IntPoint::zero(), contentBounds());
+    // Don't inflate an empty rect.
+    if (visibleContentRect.isEmpty())
+        return visibleContentRect;
 
-    // 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 (visibleContentRect.isEmpty()) {
-        bool isSmallLayer = m_tiler->numTilesX() <= 9 && m_tiler->numTilesY() <= 9 && m_tiler->numTilesX() * m_tiler->numTilesY() <= 9;
-        if ((drawTransformIsAnimating() || screenSpaceTransformIsAnimating()) && isSmallLayer)
-            return contentRect;
-        return IntRect();
-    }
-
     // FIXME: This can be made a lot larger now! We should increase
     //        this slowly while insuring it doesn't cause any perf issues.
     IntRect prepaintRect = visibleContentRect;
     prepaintRect.inflateX(m_tiler->tileSize().width());
     prepaintRect.inflateY(m_tiler->tileSize().height() * 2);
+    IntRect contentRect(IntPoint::zero(), contentBounds());
     prepaintRect.intersect(contentRect);
 
     return prepaintRect;

Modified: trunk/Source/WebCore/platform/graphics/chromium/cc/CCLayerTilingData.cpp (125497 => 125498)


--- trunk/Source/WebCore/platform/graphics/chromium/cc/CCLayerTilingData.cpp	2012-08-14 02:10:43 UTC (rev 125497)
+++ trunk/Source/WebCore/platform/graphics/chromium/cc/CCLayerTilingData.cpp	2012-08-14 02:14:16 UTC (rev 125498)
@@ -101,6 +101,11 @@
 
 void CCLayerTilingData::contentRectToTileIndices(const IntRect& contentRect, int& left, int& top, int& right, int& bottom) const
 {
+    // An empty rect doesn't result in an empty set of tiles, so don't pass an empty rect.
+    // FIXME: Possibly we should fill a vector of tiles instead,
+    //        since the normal use of this function is to enumerate some tiles.
+    ASSERT(!contentRect.isEmpty());
+
     left = m_tilingData.tileXIndexFromSrcCoord(contentRect.x());
     top = m_tilingData.tileYIndexFromSrcCoord(contentRect.y());
     right = m_tilingData.tileXIndexFromSrcCoord(contentRect.maxX() - 1);
@@ -138,6 +143,10 @@
 void CCLayerTilingData::setBounds(const IntSize& size)
 {
     m_tilingData.setTotalSize(size);
+    if (size.isEmpty()) {
+        m_tiles.clear();
+        return;
+    }
 
     // Any tiles completely outside our new bounds are invalid and should be dropped.
     int left, top, right, bottom;

Modified: trunk/Source/WebCore/platform/graphics/chromium/cc/CCPriorityCalculator.h (125497 => 125498)


--- trunk/Source/WebCore/platform/graphics/chromium/cc/CCPriorityCalculator.h	2012-08-14 02:10:43 UTC (rev 125497)
+++ trunk/Source/WebCore/platform/graphics/chromium/cc/CCPriorityCalculator.h	2012-08-14 02:14:16 UTC (rev 125498)
@@ -45,6 +45,7 @@
     static inline int lowestPriority() { return std::numeric_limits<int>::max(); }
     static inline bool priorityIsLower(int a, int b) { return a > b; }
     static inline bool priorityIsHigher(int a, int b) { return a < b; }
+    static inline bool maxPriority(int a, int b) { return priorityIsHigher(a, b) ? a : b; }
 };
 
 }

Modified: trunk/Source/WebKit/chromium/ChangeLog (125497 => 125498)


--- trunk/Source/WebKit/chromium/ChangeLog	2012-08-14 02:10:43 UTC (rev 125497)
+++ trunk/Source/WebKit/chromium/ChangeLog	2012-08-14 02:14:16 UTC (rev 125498)
@@ -1,3 +1,14 @@
+2012-08-13  Eric Penner  <[email protected]>
+
+        [chromium] Paint animated layers immediately to avoid animation hiccups.
+        https://bugs.webkit.org/show_bug.cgi?id=93028
+
+        Reviewed by Adrienne Walker.
+
+        Replaced one test. Test painting full animated layer.
+
+        * tests/TiledLayerChromiumTest.cpp:
+
 2012-08-12  Shawn Singh  <[email protected]>
 
         [chromium] renderSurface in incorrect space if owning layer has empty but non-zero bounds

Modified: trunk/Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp (125497 => 125498)


--- trunk/Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp	2012-08-14 02:10:43 UTC (rev 125497)
+++ trunk/Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp	2012-08-14 02:14:16 UTC (rev 125498)
@@ -497,6 +497,72 @@
     EXPECT_TRUE(layer2Impl->hasTileAt(0, 1));
 }
 
+TEST_F(TiledLayerChromiumTest, paintSmallAnimatedLayersImmediately)
+{
+    // Create a CCLayerTreeHost that has the right viewportsize,
+    // so the layer is considered small enough.
+    WebKit::WebCompositor::initialize(0);
+    FakeCCLayerTreeHostClient fakeCCLayerTreeHostClient;
+    OwnPtr<CCLayerTreeHost> ccLayerTreeHost = CCLayerTreeHost::create(&fakeCCLayerTreeHostClient, CCLayerTreeSettings());
+
+    bool runOutOfMemory[2] = {false, true};
+    for (int i = 0; i < 2; i++) {
+        // Create a layer with 4x4 tiles.
+        int layerWidth  = 4 * FakeTiledLayerChromium::tileSize().width();
+        int layerHeight = 4 * FakeTiledLayerChromium::tileSize().height();
+        int memoryForLayer = layerWidth * layerHeight * 4;
+        IntSize viewportSize = IntSize(layerWidth, layerHeight);
+        ccLayerTreeHost->setViewportSize(viewportSize, viewportSize);
+
+        // Use 8x4 tiles to run out of memory.
+        if (runOutOfMemory[i])
+            layerWidth *= 2;
+
+        OwnPtr<CCPrioritizedTextureManager> textureManager = CCPrioritizedTextureManager::create(memoryForLayer, 1024, CCRenderer::ContentPool);
+        DebugScopedSetImplThread implThread;
+
+        RefPtr<FakeTiledLayerChromium> layer = adoptRef(new FakeTiledLayerChromium(textureManager.get()));
+        OwnPtr<FakeCCTiledLayerImpl> layerImpl(adoptPtr(new FakeCCTiledLayerImpl(1)));
+
+        // Full size layer with half being visible.
+        IntSize contentBounds(layerWidth, layerHeight);
+        IntRect contentRect(IntPoint::zero(), contentBounds);
+        IntRect visibleRect(IntPoint::zero(), IntSize(layerWidth / 2, layerHeight));
+
+        // Pretend the layer is animating.
+        layer->setDrawTransformIsAnimating(true);
+        layer->setBounds(contentBounds);
+        layer->setVisibleContentRect(visibleRect);
+        layer->invalidateContentRect(contentRect);
+        layer->setLayerTreeHost(ccLayerTreeHost.get());
+
+        // The layer should paint it's entire contents on the first paint
+        // if it is close to the viewport size and has the available memory.
+        layer->setTexturePriorities(m_priorityCalculator);
+        textureManager->prioritizeTextures();
+        layer->updateContentRect(m_queue, visibleRect, 0, m_stats);
+        updateTextures();
+        layer->pushPropertiesTo(layerImpl.get());
+
+        // We should have all the tiles for the small animated layer.
+        // We should still have the visible tiles when we didn't
+        // have enough memory for all the tiles.
+        if (!runOutOfMemory[i]) {
+            for (int i = 0; i < 4; ++i) {
+                for (int j = 0; j < 4; ++j)
+                    EXPECT_TRUE(layerImpl->hasTileAt(i, j));
+            }
+        } else {
+            for (int i = 0; i < 8; ++i) {
+                for (int j = 0; j < 4; ++j)
+                    EXPECT_EQ(layerImpl->hasTileAt(i, j), i < 4);
+            }
+        }
+    }
+    ccLayerTreeHost.clear();
+    WebKit::WebCompositor::shutdown();
+}
+
 TEST_F(TiledLayerChromiumTest, idlePaintOutOfMemory)
 {
     // The tile size is 100x100. Setup 3x3 tiles with one 1x1 visible tile in the center.
@@ -581,108 +647,47 @@
     IntSize contentBounds(100, 100);
     IntRect contentRect(IntPoint::zero(), contentBounds);
 
-    OwnPtr<CCPrioritizedTextureManager> textureManager = CCPrioritizedTextureManager::create(20000, 1024, CCRenderer::ContentPool);
+    OwnPtr<CCPrioritizedTextureManager> textureManager = CCPrioritizedTextureManager::create(4*1024*1024, 1024, CCRenderer::ContentPool);
     RefPtr<FakeTiledLayerChromium> layer = adoptRef(new FakeTiledLayerChromium(textureManager.get()));
     DebugScopedSetImplThread implThread;
     OwnPtr<FakeCCTiledLayerImpl> layerImpl(adoptPtr(new FakeCCTiledLayerImpl(1)));
+    layer->setBounds(contentBounds);
 
-    // Invalidate the layer but make none of it visible, so nothing paints.
-    IntRect visibleRect;
+    // Alternate between not visible and visible.
+    IntRect v(0, 0, 100, 100);
+    IntRect nv(0, 0, 0, 0);
+    IntRect visibleRect[10] = {nv, nv, v, v, nv, nv, v, v, nv, nv};
+    bool invalidate[10] =  {true, true, true, true, true, true, true, true, false, false };
 
-    layer->setBounds(contentBounds);
-    layer->setVisibleContentRect(visibleRect);
-    layer->invalidateContentRect(contentRect);
+    // We should not have any tiles except for when the layer was visible
+    // or after the layer was visible and we didn't invalidate.
+    bool haveTile[10] = { false, false, true, true, false, false, true, true, true, true };
 
-    for (int i = 0; i < 2; i++) {
+    for (int i = 0; i < 10; i++) {
+        layer->setVisibleContentRect(visibleRect[i]);
+
+        // Skip invalidation once to insure the tile stays in memory while not visible.
+        if (invalidate[i])
+            layer->invalidateContentRect(contentRect);
+
         // Paint / idle-paint.
+        textureManager->clearPriorities();
         layer->setTexturePriorities(m_priorityCalculator);
         textureManager->prioritizeTextures();
-        layer->updateContentRect(m_queue, visibleRect, 0, m_stats);
+        layer->updateContentRect(m_queue, visibleRect[i], 0, m_stats);
 
-        // Non-visible layers don't need idle paint.
-        EXPECT_FALSE(layer->needsIdlePaint(visibleRect));
+        updateTextures();
 
+        // We should never signal idle paint, as we painted the entire layer
+        // or the layer was not visible.
+        EXPECT_FALSE(layer->needsIdlePaint(visibleRect[i]));
+
         layer->pushPropertiesTo(layerImpl.get());
-
-        // We should not have any tiles pushed since the layer is not visible.
-        EXPECT_FALSE(layerImpl->hasTileAt(0, 0));
+        EXPECT_EQ(layerImpl->hasTileAt(0, 0), haveTile[i]);
     }
 }
 
-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_F(TiledLayerChromiumTest, idlePaintNonVisibleAnimatingLayers)
-{
-    OwnPtr<CCPrioritizedTextureManager> textureManager = CCPrioritizedTextureManager::create(8000*8000*8, 1024, CCRenderer::ContentPool);
-    DebugScopedSetImplThread implThread;
-
-    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(1)));
-
-            // 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->setVisibleContentRect(visibleRect);
-            layer->invalidateContentRect(contentRect);
-
-            layer->setTexturePriorities(m_priorityCalculator);
-            textureManager->prioritizeTextures();
-
-            // If idlePaintRect gives back a non-empty result then we should paint it. Otherwise,
-            // we shoud paint nothing.
-            bool shouldPrepaint = !layer->idlePaintRect(visibleRect).isEmpty();
-
-            // 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.
-            for (int k = 0; k < 4; ++k) {
-                layer->setTexturePriorities(m_priorityCalculator);
-                textureManager->prioritizeTextures();
-
-                layer->updateContentRect(m_queue, visibleRect, 0, m_stats);
-                updateTextures();
-                layer->pushPropertiesTo(layerImpl.get());
-            }
-
-            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));
-            for (int k = 0; k < 4; ++k) {
-                layer->setTexturePriorities(m_priorityCalculator);
-                textureManager->prioritizeTextures();
-
-                layer->updateContentRect(m_queue, visibleRect, 0, m_stats);
-                updateTextures();
-                layer->pushPropertiesTo(layerImpl.get());
-            }
-
-            testHaveOuterTiles(layerImpl.get(), width[i], height[j], shouldPrepaint ? 1 : 0);
-        }
-    }
-}
-
 TEST_F(TiledLayerChromiumTest, invalidateFromPrepare)
 {
     OwnPtr<CCPrioritizedTextureManager> textureManager = CCPrioritizedTextureManager::create(4*1024*1024, 1024, CCRenderer::ContentPool);
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to