Modified: trunk/Source/WebCore/platform/graphics/chromium/TiledLayerChromium.cpp (125259 => 125260)
--- trunk/Source/WebCore/platform/graphics/chromium/TiledLayerChromium.cpp 2012-08-10 08:08:18 UTC (rev 125259)
+++ trunk/Source/WebCore/platform/graphics/chromium/TiledLayerChromium.cpp 2012-08-10 08:16:25 UTC (rev 125260)
@@ -560,77 +560,31 @@
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();
- if (m_tiler->hasEmptyBounds())
- return;
-
+ IntRect prepaintRect = idlePaintRect(visibleContentRect);
bool drawsToRoot = !renderTarget()->parent();
- bool smallAnimatedLayer = isSmallAnimatedLayer(this);
// Minimally create the tiles in the desired pre-paint rect.
- IntRect createTilesRect = idlePaintRect(visibleContentRect);
- if (!createTilesRect.isEmpty()) {
+ if (!prepaintRect.isEmpty()) {
int left, top, right, bottom;
- m_tiler->contentRectToTileIndices(createTilesRect, left, top, right, bottom);
- for (int j = top; j <= bottom; ++j) {
- for (int i = left; i <= right; ++i) {
+ m_tiler->contentRectToTileIndices(prepaintRect, 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 they 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 (!doubleBufferedRect.isEmpty()) {
+ if (!visibleContentRect.isEmpty()) {
int left, top, right, bottom;
- m_tiler->contentRectToTileIndices(doubleBufferedRect, left, top, right, bottom);
+ m_tiler->contentRectToTileIndices(visibleContentRect, left, top, right, bottom);
for (int j = top; j <= bottom; ++j) {
for (int i = left; i <= right; ++i) {
UpdatableTile* tile = tileAt(i, j);
@@ -646,10 +600,9 @@
continue;
}
- IntRect tileRect = m_tiler->tileRect(tile);
- tile->dirtyRect = tileRect;
+ tile->dirtyRect = m_tiler->tileRect(tile);
LayerTextureUpdater::Texture* backBuffer = tile->texture();
- setPriorityForTexture(priorityCalc, visibleContentRect, tile->dirtyRect, drawsToRoot, smallAnimatedLayer, backBuffer->texture());
+ backBuffer->texture()->setRequestPriority(priorityCalc.priorityFromVisibility(true, drawsToRoot));
OwnPtr<CCPrioritizedTexture> frontBuffer = CCPrioritizedTexture::create(backBuffer->texture()->textureManager(),
backBuffer->texture()->size(),
backBuffer->texture()->format());
@@ -660,14 +613,18 @@
}
}
- // Now update priorities on all tiles we have in the layer, no matter where they are.
+ // Now set priorities on all tiles.
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);
- setPriorityForTexture(priorityCalc, visibleContentRect, tileRect, drawsToRoot, smallAnimatedLayer, tile->managedTexture());
+ // 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));
}
}
@@ -703,45 +660,45 @@
bool didPaint = false;
- // 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)) {
+ // Visible painting. Only paint visible tiles if the visible rect isn't empty.
+ if (!contentRect.isEmpty()) {
int left, top, right, bottom;
- m_tiler->contentRectToTileIndices(IntRect(IntPoint::zero(), contentBounds()), left, top, right, bottom);
- updateTiles(left, top, right, bottom, queue, 0, stats, didPaint);
- if (didPaint)
+ 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;
- // 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) {
@@ -785,6 +742,9 @@
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)
@@ -804,6 +764,16 @@
{
IntRect contentRect(IntPoint::zero(), contentBounds());
+ // 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;
Modified: trunk/Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp (125259 => 125260)
--- trunk/Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp 2012-08-10 08:08:18 UTC (rev 125259)
+++ trunk/Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp 2012-08-10 08:16:25 UTC (rev 125260)
@@ -497,72 +497,6 @@
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.
@@ -675,7 +609,80 @@
}
}
+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);