Chromium Code Reviews| Index: cc/tiled_layer.cc |
| diff --git a/cc/tiled_layer.cc b/cc/tiled_layer.cc |
| index 1ea1e25fde49a6eb6953e51bdab2351c2f9cd725..ff88db7929c719b2e4b1aaf4ae105ffe7a6b35fb 100644 |
| --- a/cc/tiled_layer.cc |
| +++ b/cc/tiled_layer.cc |
| @@ -568,6 +568,7 @@ void TiledLayerChromium::setTexturePriorities(const CCPriorityCalculator& priori |
| { |
| updateBounds(); |
| resetUpdateState(); |
| + updateScrollPrediction(); |
| if (m_tiler->hasEmptyBounds()) |
| return; |
| @@ -637,7 +638,7 @@ void TiledLayerChromium::setTexturePriorities(const CCPriorityCalculator& priori |
| if (!tile) |
| continue; |
| IntRect tileRect = m_tiler->tileRect(tile); |
| - setPriorityForTexture(visibleContentRect(), tileRect, drawsToRoot, smallAnimatedLayer, tile->managedTexture()); |
| + setPriorityForTexture(m_predictedVisibleRect, tileRect, drawsToRoot, smallAnimatedLayer, tile->managedTexture()); |
| } |
| } |
| @@ -665,6 +666,46 @@ void TiledLayerChromium::resetUpdateState() |
| } |
| } |
| +namespace { |
| +IntRect expandRectByDelta(IntRect rect, IntSize delta) { |
| + int width = rect.width() + abs(delta.width()); |
| + int height = rect.height() + abs(delta.height()); |
| + int x = rect.x() + ((delta.width() < 0) ? delta.width() : 0); |
|
enne (OOO)
2012/10/18 19:13:08
Why do you need this clamping on the negative end,
epennerAtGoogle
2012/10/18 19:58:55
When expanding a rect in the direction of an arbit
enne (OOO)
2012/10/19 18:40:56
Ah, gotcha, thanks.
|
| + int y = rect.y() + ((delta.height() < 0) ? delta.height() : 0); |
| + return IntRect(x, y, width, height); |
| +} |
| +} |
| + |
| +void TiledLayerChromium::updateScrollPrediction() |
| +{ |
| + // This scroll prediction is very primitive and should be replaced by a |
| + // a recursive calculation on all layers which uses actual scroll/animation |
| + // velocities. To insure this doesn't miss-predict, we only use it to predict |
| + // the visibleRect if: |
| + // - contentBounds() hasn't changed. |
| + // - visibleRect.size() hasn't changed. |
| + // These two conditions prevent rotations, scales, pinch-zooms etc. where |
| + // the prediction would be incorrect. |
| + IntSize delta = visibleContentRect().center() - m_previousVisibleRect.center(); |
| + m_predictedScroll = -delta; |
| + m_predictedVisibleRect = visibleContentRect(); |
| + if (m_previousContentBounds == contentBounds() && m_previousVisibleRect.size() == visibleContentRect().size()) { |
| + // Only expand the visible rect in the major scroll direction, to prevent |
| + // massive paints due to diagonal scrolls. |
| + IntSize majorScrollAxis = (abs(delta.width()) > abs(delta.height())) ? IntSize(delta.width(), 0) : IntSize(0, delta.height()); |
| + m_predictedVisibleRect = expandRectByDelta(visibleContentRect(), majorScrollAxis); |
| + |
| + // Bound the prediction to at most 2 tiles, and clamp to content bounds. |
|
enne (OOO)
2012/10/18 19:13:08
The 2 tiles ahead guess seems a little magical. H
epennerAtGoogle
2012/10/18 19:58:55
There needs to be some kind of clamp to prevent ar
|
| + IntRect bound = visibleContentRect(); |
| + bound.inflateX(m_tiler->tileSize().width() * 2); |
| + bound.inflateY(m_tiler->tileSize().height() * 2); |
| + bound.intersect(IntRect(IntPoint::zero(), contentBounds())); |
| + m_predictedVisibleRect.intersect(bound); |
| + } |
| + m_previousContentBounds = contentBounds(); |
| + m_previousVisibleRect = visibleContentRect(); |
| +} |
| + |
| void TiledLayerChromium::update(CCTextureUpdateQueue& queue, const CCOcclusionTracker* occlusion, CCRenderingStats& stats) |
| { |
| ASSERT(!m_skipsDraw && !m_failedUpdate); // Did resetUpdateState get skipped? |
| @@ -688,12 +729,12 @@ void TiledLayerChromium::update(CCTextureUpdateQueue& queue, const CCOcclusionTr |
| m_failedUpdate = false; |
| } |
| - if (visibleContentRect().isEmpty()) |
| + if (m_predictedVisibleRect.isEmpty()) |
| return; |
| // Visible painting. First occlude visible tiles and paint the non-occluded tiles. |
| int left, top, right, bottom; |
| - m_tiler->contentRectToTileIndices(visibleContentRect(), left, top, right, bottom); |
| + m_tiler->contentRectToTileIndices(m_predictedVisibleRect, left, top, right, bottom); |
| markOcclusionsAndRequestTextures(left, top, right, bottom, occlusion); |
| m_skipsDraw = !updateTiles(left, top, right, bottom, queue, occlusion, stats, didPaint); |
| if (m_skipsDraw) |
| @@ -713,27 +754,42 @@ void TiledLayerChromium::update(CCTextureUpdateQueue& queue, const CCOcclusionTr |
| int prepaintLeft, prepaintTop, prepaintRight, prepaintBottom; |
| m_tiler->contentRectToTileIndices(idlePaintContentRect, prepaintLeft, prepaintTop, prepaintRight, prepaintBottom); |
| - // 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) { |
| - ++bottom; |
| - if (!updateTiles(left, bottom, right, bottom, queue, 0, stats, didPaint) || didPaint) |
| - return; |
| + // Then expand outwards one row/column at a time until we find a dirty row/column |
| + // to update. Increment along the major and minor scroll directions first. |
| + IntSize delta = -m_predictedScroll; |
| + delta = IntSize(delta.width() == 0 ? 1 : delta.width(), |
| + delta.height() == 0 ? 1 : delta.height()); |
| + IntSize majorDelta = (abs(delta.width()) > abs(delta.height())) ? IntSize(delta.width(), 0) : IntSize(0, delta.height()); |
| + IntSize minorDelta = (abs(delta.width()) <= abs(delta.height())) ? IntSize(delta.width(), 0) : IntSize(0, delta.height()); |
| + IntSize deltas[4] = {majorDelta, minorDelta, -majorDelta, -minorDelta}; |
| + for(int i = 0; i < 4; i++) { |
| + if (deltas[i].height() > 0) { |
| + while (bottom < prepaintBottom) { |
| + ++bottom; |
| + if (!updateTiles(left, bottom, right, bottom, queue, 0, stats, didPaint) || didPaint) |
| + return; |
| + } |
| } |
| - if (top > prepaintTop) { |
| - --top; |
| - if (!updateTiles(left, top, right, top, queue, 0, stats, didPaint) || didPaint) |
| - return; |
| + if (deltas[i].height() < 0) { |
| + while (top > prepaintTop) { |
| + --top; |
| + if (!updateTiles(left, top, right, top, queue, 0, stats, didPaint) || didPaint) |
| + return; |
| + } |
| } |
| - if (left > prepaintLeft) { |
| - --left; |
| - if (!updateTiles(left, top, left, bottom, queue, 0, stats, didPaint) || didPaint) |
| - return; |
| + if (deltas[i].width() < 0) { |
| + while (left > prepaintLeft) { |
| + --left; |
| + if (!updateTiles(left, top, left, bottom, queue, 0, stats, didPaint) || didPaint) |
| + return; |
| + } |
| } |
| - if (right < prepaintRight) { |
| - ++right; |
| - if (!updateTiles(right, top, right, bottom, queue, 0, stats, didPaint) || didPaint) |
| - return; |
| + if (deltas[i].width() > 0) { |
| + while (right < prepaintRight) { |
| + ++right; |
| + if (!updateTiles(right, top, right, bottom, queue, 0, stats, didPaint) || didPaint) |
| + return; |
| + } |
| } |
| } |
| } |
| @@ -777,8 +833,8 @@ IntRect TiledLayerChromium::idlePaintRect() |
| // 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); |
| + prepaintRect.inflateX(m_tiler->tileSize().width() * 2); |
| + prepaintRect.inflateY(m_tiler->tileSize().height() * 4); |
| IntRect contentRect(IntPoint::zero(), contentBounds()); |
| prepaintRect.intersect(contentRect); |