| OLD | NEW |
| 1 // Copyright 2011 The Chromium Authors. All rights reserved. | 1 // Copyright 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "config.h" | 5 #include "config.h" |
| 6 | 6 |
| 7 #include "cc/tiled_layer.h" | 7 #include "cc/tiled_layer.h" |
| 8 | 8 |
| 9 #include "CCLayerImpl.h" | 9 #include "CCLayerImpl.h" |
| 10 #include "CCLayerTreeHost.h" | 10 #include "CCLayerTreeHost.h" |
| 11 #include "Region.h" | 11 #include "Region.h" |
| 12 #include "base/basictypes.h" | 12 #include "base/basictypes.h" |
| 13 #include "cc/overdraw_metrics.h" | 13 #include "cc/overdraw_metrics.h" |
| 14 #include "cc/tiled_layer_impl.h" | 14 #include "cc/tiled_layer_impl.h" |
| 15 #include "third_party/khronos/GLES2/gl2.h" | 15 #include "third_party/khronos/GLES2/gl2.h" |
| 16 | 16 |
| 17 using namespace std; | 17 using namespace std; |
| 18 using WebKit::WebTransformationMatrix; | 18 using WebKit::WebTransformationMatrix; |
| 19 | 19 |
| 20 namespace cc { | 20 namespace cc { |
| 21 | 21 |
| 22 // Maximum predictive expansion of the visible area. |
| 23 static const int maxPredictiveTilesCount = 2; |
| 24 |
| 25 // Number of rows/columns of tiles to pre-paint. |
| 26 // We should increase these further as all textures are |
| 27 // prioritized and we insure performance doesn't suffer. |
| 28 static const int prepaintRows = 4; |
| 29 static const int prepaintColumns = 2; |
| 30 |
| 31 |
| 22 class UpdatableTile : public LayerTilingData::Tile { | 32 class UpdatableTile : public LayerTilingData::Tile { |
| 23 public: | 33 public: |
| 24 static scoped_ptr<UpdatableTile> create(scoped_ptr<LayerTextureUpdater::Text
ure> texture) | 34 static scoped_ptr<UpdatableTile> create(scoped_ptr<LayerTextureUpdater::Text
ure> texture) |
| 25 { | 35 { |
| 26 return make_scoped_ptr(new UpdatableTile(texture.Pass())); | 36 return make_scoped_ptr(new UpdatableTile(texture.Pass())); |
| 27 } | 37 } |
| 28 | 38 |
| 29 LayerTextureUpdater::Texture* texture() { return m_texture.get(); } | 39 LayerTextureUpdater::Texture* texture() { return m_texture.get(); } |
| 30 PrioritizedTexture* managedTexture() { return m_texture->texture(); } | 40 PrioritizedTexture* managedTexture() { return m_texture->texture(); } |
| 31 | 41 |
| (...skipping 527 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 559 priority = PriorityCalculator::maxPriority(priority, PriorityCalculator:
:smallAnimatedLayerMinPriority()); | 569 priority = PriorityCalculator::maxPriority(priority, PriorityCalculator:
:smallAnimatedLayerMinPriority()); |
| 560 if (priority != PriorityCalculator::lowestPriority()) | 570 if (priority != PriorityCalculator::lowestPriority()) |
| 561 texture->setRequestPriority(priority); | 571 texture->setRequestPriority(priority); |
| 562 } | 572 } |
| 563 } | 573 } |
| 564 | 574 |
| 565 void TiledLayer::setTexturePriorities(const PriorityCalculator& priorityCalc) | 575 void TiledLayer::setTexturePriorities(const PriorityCalculator& priorityCalc) |
| 566 { | 576 { |
| 567 updateBounds(); | 577 updateBounds(); |
| 568 resetUpdateState(); | 578 resetUpdateState(); |
| 579 updateScrollPrediction(); |
| 569 | 580 |
| 570 if (m_tiler->hasEmptyBounds()) | 581 if (m_tiler->hasEmptyBounds()) |
| 571 return; | 582 return; |
| 572 | 583 |
| 573 bool drawsToRoot = !renderTarget()->parent(); | 584 bool drawsToRoot = !renderTarget()->parent(); |
| 574 bool smallAnimatedLayer = isSmallAnimatedLayer(this); | 585 bool smallAnimatedLayer = isSmallAnimatedLayer(this); |
| 575 | 586 |
| 576 // Minimally create the tiles in the desired pre-paint rect. | 587 // Minimally create the tiles in the desired pre-paint rect. |
| 577 IntRect createTilesRect = idlePaintRect(); | 588 IntRect createTilesRect = idlePaintRect(); |
| 578 if (!createTilesRect.isEmpty()) { | 589 if (!createTilesRect.isEmpty()) { |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 628 } | 639 } |
| 629 } | 640 } |
| 630 | 641 |
| 631 // Now update priorities on all tiles we have in the layer, no matter where
they are. | 642 // Now update priorities on all tiles we have in the layer, no matter where
they are. |
| 632 for (LayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(
); iter != m_tiler->tiles().end(); ++iter) { | 643 for (LayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(
); iter != m_tiler->tiles().end(); ++iter) { |
| 633 UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second); | 644 UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second); |
| 634 // FIXME: This should not ever be null. | 645 // FIXME: This should not ever be null. |
| 635 if (!tile) | 646 if (!tile) |
| 636 continue; | 647 continue; |
| 637 IntRect tileRect = m_tiler->tileRect(tile); | 648 IntRect tileRect = m_tiler->tileRect(tile); |
| 638 setPriorityForTexture(visibleContentRect(), tileRect, drawsToRoot, small
AnimatedLayer, tile->managedTexture()); | 649 setPriorityForTexture(m_predictedVisibleRect, tileRect, drawsToRoot, sma
llAnimatedLayer, tile->managedTexture()); |
| 639 } | 650 } |
| 640 } | 651 } |
| 641 | 652 |
| 642 Region TiledLayer::visibleContentOpaqueRegion() const | 653 Region TiledLayer::visibleContentOpaqueRegion() const |
| 643 { | 654 { |
| 644 if (m_skipsDraw) | 655 if (m_skipsDraw) |
| 645 return Region(); | 656 return Region(); |
| 646 if (contentsOpaque()) | 657 if (contentsOpaque()) |
| 647 return visibleContentRect(); | 658 return visibleContentRect(); |
| 648 return m_tiler->opaqueRegionInContentRect(visibleContentRect()); | 659 return m_tiler->opaqueRegionInContentRect(visibleContentRect()); |
| 649 } | 660 } |
| 650 | 661 |
| 651 void TiledLayer::resetUpdateState() | 662 void TiledLayer::resetUpdateState() |
| 652 { | 663 { |
| 653 m_skipsDraw = false; | 664 m_skipsDraw = false; |
| 654 m_failedUpdate = false; | 665 m_failedUpdate = false; |
| 655 | 666 |
| 656 LayerTilingData::TileMap::const_iterator end = m_tiler->tiles().end(); | 667 LayerTilingData::TileMap::const_iterator end = m_tiler->tiles().end(); |
| 657 for (LayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(
); iter != end; ++iter) { | 668 for (LayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(
); iter != end; ++iter) { |
| 658 UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second); | 669 UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second); |
| 659 // FIXME: This should not ever be null. | 670 // FIXME: This should not ever be null. |
| 660 if (!tile) | 671 if (!tile) |
| 661 continue; | 672 continue; |
| 662 tile->resetUpdateState(); | 673 tile->resetUpdateState(); |
| 663 } | 674 } |
| 664 } | 675 } |
| 665 | 676 |
| 677 namespace { |
| 678 IntRect expandRectByDelta(IntRect rect, IntSize delta) { |
| 679 int width = rect.width() + abs(delta.width()); |
| 680 int height = rect.height() + abs(delta.height()); |
| 681 int x = rect.x() + ((delta.width() < 0) ? delta.width() : 0); |
| 682 int y = rect.y() + ((delta.height() < 0) ? delta.height() : 0); |
| 683 return IntRect(x, y, width, height); |
| 684 } |
| 685 } |
| 686 |
| 687 void TiledLayer::updateScrollPrediction() |
| 688 { |
| 689 // This scroll prediction is very primitive and should be replaced by a |
| 690 // a recursive calculation on all layers which uses actual scroll/animation |
| 691 // velocities. To insure this doesn't miss-predict, we only use it to predic
t |
| 692 // the visibleRect if: |
| 693 // - contentBounds() hasn't changed. |
| 694 // - visibleRect.size() hasn't changed. |
| 695 // These two conditions prevent rotations, scales, pinch-zooms etc. where |
| 696 // the prediction would be incorrect. |
| 697 IntSize delta = visibleContentRect().center() - m_previousVisibleRect.center
(); |
| 698 m_predictedScroll = -delta; |
| 699 m_predictedVisibleRect = visibleContentRect(); |
| 700 if (m_previousContentBounds == contentBounds() && m_previousVisibleRect.size
() == visibleContentRect().size()) { |
| 701 // Only expand the visible rect in the major scroll direction, to preven
t |
| 702 // massive paints due to diagonal scrolls. |
| 703 IntSize majorScrollDelta = (abs(delta.width()) > abs(delta.height())) ?
IntSize(delta.width(), 0) : IntSize(0, delta.height()); |
| 704 m_predictedVisibleRect = expandRectByDelta(visibleContentRect(), majorSc
rollDelta); |
| 705 |
| 706 // Bound the prediction to prevent unbounded paints, and clamp to conten
t bounds. |
| 707 IntRect bound = visibleContentRect(); |
| 708 bound.inflateX(m_tiler->tileSize().width() * maxPredictiveTilesCount); |
| 709 bound.inflateY(m_tiler->tileSize().height() * maxPredictiveTilesCount); |
| 710 bound.intersect(IntRect(IntPoint::zero(), contentBounds())); |
| 711 m_predictedVisibleRect.intersect(bound); |
| 712 } |
| 713 m_previousContentBounds = contentBounds(); |
| 714 m_previousVisibleRect = visibleContentRect(); |
| 715 } |
| 716 |
| 666 void TiledLayer::update(TextureUpdateQueue& queue, const OcclusionTracker* occlu
sion, RenderingStats& stats) | 717 void TiledLayer::update(TextureUpdateQueue& queue, const OcclusionTracker* occlu
sion, RenderingStats& stats) |
| 667 { | 718 { |
| 668 DCHECK(!m_skipsDraw && !m_failedUpdate); // Did resetUpdateState get skipped
? | 719 DCHECK(!m_skipsDraw && !m_failedUpdate); // Did resetUpdateState get skipped
? |
| 669 updateBounds(); | 720 updateBounds(); |
| 670 if (m_tiler->hasEmptyBounds() || !drawsContent()) | 721 if (m_tiler->hasEmptyBounds() || !drawsContent()) |
| 671 return; | 722 return; |
| 672 | 723 |
| 673 bool didPaint = false; | 724 bool didPaint = false; |
| 674 | 725 |
| 675 // Animation pre-paint. If the layer is small, try to paint it all | 726 // Animation pre-paint. If the layer is small, try to paint it all |
| 676 // immediately whether or not it is occluded, to avoid paint/upload | 727 // immediately whether or not it is occluded, to avoid paint/upload |
| 677 // hiccups while it is animating. | 728 // hiccups while it is animating. |
| 678 if (isSmallAnimatedLayer(this)) { | 729 if (isSmallAnimatedLayer(this)) { |
| 679 int left, top, right, bottom; | 730 int left, top, right, bottom; |
| 680 m_tiler->contentRectToTileIndices(IntRect(IntPoint::zero(), contentBound
s()), left, top, right, bottom); | 731 m_tiler->contentRectToTileIndices(IntRect(IntPoint::zero(), contentBound
s()), left, top, right, bottom); |
| 681 updateTiles(left, top, right, bottom, queue, 0, stats, didPaint); | 732 updateTiles(left, top, right, bottom, queue, 0, stats, didPaint); |
| 682 if (didPaint) | 733 if (didPaint) |
| 683 return; | 734 return; |
| 684 // This was an attempt to paint the entire layer so if we fail it's okay
, | 735 // This was an attempt to paint the entire layer so if we fail it's okay
, |
| 685 // just fallback on painting visible etc. below. | 736 // just fallback on painting visible etc. below. |
| 686 m_failedUpdate = false; | 737 m_failedUpdate = false; |
| 687 } | 738 } |
| 688 | 739 |
| 689 if (visibleContentRect().isEmpty()) | 740 if (m_predictedVisibleRect.isEmpty()) |
| 690 return; | 741 return; |
| 691 | 742 |
| 692 // Visible painting. First occlude visible tiles and paint the non-occluded
tiles. | 743 // Visible painting. First occlude visible tiles and paint the non-occluded
tiles. |
| 693 int left, top, right, bottom; | 744 int left, top, right, bottom; |
| 694 m_tiler->contentRectToTileIndices(visibleContentRect(), left, top, right, bo
ttom); | 745 m_tiler->contentRectToTileIndices(m_predictedVisibleRect, left, top, right,
bottom); |
| 695 markOcclusionsAndRequestTextures(left, top, right, bottom, occlusion); | 746 markOcclusionsAndRequestTextures(left, top, right, bottom, occlusion); |
| 696 m_skipsDraw = !updateTiles(left, top, right, bottom, queue, occlusion, stats
, didPaint); | 747 m_skipsDraw = !updateTiles(left, top, right, bottom, queue, occlusion, stats
, didPaint); |
| 697 if (m_skipsDraw) | 748 if (m_skipsDraw) |
| 698 m_tiler->reset(); | 749 m_tiler->reset(); |
| 699 if (m_skipsDraw || didPaint) | 750 if (m_skipsDraw || didPaint) |
| 700 return; | 751 return; |
| 701 | 752 |
| 702 // If we have already painting everything visible. Do some pre-painting whil
e idle. | 753 // If we have already painting everything visible. Do some pre-painting whil
e idle. |
| 703 IntRect idlePaintContentRect = idlePaintRect(); | 754 IntRect idlePaintContentRect = idlePaintRect(); |
| 704 if (idlePaintContentRect.isEmpty()) | 755 if (idlePaintContentRect.isEmpty()) |
| 705 return; | 756 return; |
| 706 | 757 |
| 707 // Prepaint anything that was occluded but inside the layer's visible region
. | 758 // Prepaint anything that was occluded but inside the layer's visible region
. |
| 708 if (!updateTiles(left, top, right, bottom, queue, 0, stats, didPaint) || did
Paint) | 759 if (!updateTiles(left, top, right, bottom, queue, 0, stats, didPaint) || did
Paint) |
| 709 return; | 760 return; |
| 710 | 761 |
| 711 int prepaintLeft, prepaintTop, prepaintRight, prepaintBottom; | 762 int prepaintLeft, prepaintTop, prepaintRight, prepaintBottom; |
| 712 m_tiler->contentRectToTileIndices(idlePaintContentRect, prepaintLeft, prepai
ntTop, prepaintRight, prepaintBottom); | 763 m_tiler->contentRectToTileIndices(idlePaintContentRect, prepaintLeft, prepai
ntTop, prepaintRight, prepaintBottom); |
| 713 | 764 |
| 714 // Then expand outwards from the visible area until we find a dirty row or c
olumn to update. | 765 // Then expand outwards one row/column at a time until we find a dirty row/c
olumn |
| 715 while (left > prepaintLeft || top > prepaintTop || right < prepaintRight ||
bottom < prepaintBottom) { | 766 // to update. Increment along the major and minor scroll directions first. |
| 716 if (bottom < prepaintBottom) { | 767 IntSize delta = -m_predictedScroll; |
| 717 ++bottom; | 768 delta = IntSize(delta.width() == 0 ? 1 : delta.width(), |
| 718 if (!updateTiles(left, bottom, right, bottom, queue, 0, stats, didPa
int) || didPaint) | 769 delta.height() == 0 ? 1 : delta.height()); |
| 719 return; | 770 IntSize majorDelta = (abs(delta.width()) > abs(delta.height())) ? IntSize(d
elta.width(), 0) : IntSize(0, delta.height()); |
| 771 IntSize minorDelta = (abs(delta.width()) <= abs(delta.height())) ? IntSize(d
elta.width(), 0) : IntSize(0, delta.height()); |
| 772 IntSize deltas[4] = {majorDelta, minorDelta, -majorDelta, -minorDelta}; |
| 773 for(int i = 0; i < 4; i++) { |
| 774 if (deltas[i].height() > 0) { |
| 775 while (bottom < prepaintBottom) { |
| 776 ++bottom; |
| 777 if (!updateTiles(left, bottom, right, bottom, queue, 0, stats, d
idPaint) || didPaint) |
| 778 return; |
| 779 } |
| 720 } | 780 } |
| 721 if (top > prepaintTop) { | 781 if (deltas[i].height() < 0) { |
| 722 --top; | 782 while (top > prepaintTop) { |
| 723 if (!updateTiles(left, top, right, top, queue, 0, stats, didPaint) |
| didPaint) | 783 --top; |
| 724 return; | 784 if (!updateTiles(left, top, right, top, queue, 0, stats, didPain
t) || didPaint) |
| 785 return; |
| 786 } |
| 725 } | 787 } |
| 726 if (left > prepaintLeft) { | 788 if (deltas[i].width() < 0) { |
| 727 --left; | 789 while (left > prepaintLeft) { |
| 728 if (!updateTiles(left, top, left, bottom, queue, 0, stats, didPaint)
|| didPaint) | 790 --left; |
| 729 return; | 791 if (!updateTiles(left, top, left, bottom, queue, 0, stats, didPa
int) || didPaint) |
| 792 return; |
| 793 } |
| 730 } | 794 } |
| 731 if (right < prepaintRight) { | 795 if (deltas[i].width() > 0) { |
| 732 ++right; | 796 while (right < prepaintRight) { |
| 733 if (!updateTiles(right, top, right, bottom, queue, 0, stats, didPain
t) || didPaint) | 797 ++right; |
| 734 return; | 798 if (!updateTiles(right, top, right, bottom, queue, 0, stats, did
Paint) || didPaint) |
| 799 return; |
| 800 } |
| 735 } | 801 } |
| 736 } | 802 } |
| 737 } | 803 } |
| 738 | 804 |
| 739 bool TiledLayer::needsIdlePaint() | 805 bool TiledLayer::needsIdlePaint() |
| 740 { | 806 { |
| 741 // Don't trigger more paints if we failed (as we'll just fail again). | 807 // Don't trigger more paints if we failed (as we'll just fail again). |
| 742 if (m_failedUpdate || visibleContentRect().isEmpty() || m_tiler->hasEmptyBou
nds() || !drawsContent()) | 808 if (m_failedUpdate || visibleContentRect().isEmpty() || m_tiler->hasEmptyBou
nds() || !drawsContent()) |
| 743 return false; | 809 return false; |
| 744 | 810 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 765 } | 831 } |
| 766 return false; | 832 return false; |
| 767 } | 833 } |
| 768 | 834 |
| 769 IntRect TiledLayer::idlePaintRect() | 835 IntRect TiledLayer::idlePaintRect() |
| 770 { | 836 { |
| 771 // Don't inflate an empty rect. | 837 // Don't inflate an empty rect. |
| 772 if (visibleContentRect().isEmpty()) | 838 if (visibleContentRect().isEmpty()) |
| 773 return IntRect(); | 839 return IntRect(); |
| 774 | 840 |
| 775 // FIXME: This can be made a lot larger now! We should increase | |
| 776 // this slowly while insuring it doesn't cause any perf issues. | |
| 777 IntRect prepaintRect = visibleContentRect(); | 841 IntRect prepaintRect = visibleContentRect(); |
| 778 prepaintRect.inflateX(m_tiler->tileSize().width()); | 842 prepaintRect.inflateX(m_tiler->tileSize().width() * prepaintColumns); |
| 779 prepaintRect.inflateY(m_tiler->tileSize().height() * 2); | 843 prepaintRect.inflateY(m_tiler->tileSize().height() * prepaintRows); |
| 780 IntRect contentRect(IntPoint::zero(), contentBounds()); | 844 IntRect contentRect(IntPoint::zero(), contentBounds()); |
| 781 prepaintRect.intersect(contentRect); | 845 prepaintRect.intersect(contentRect); |
| 782 | 846 |
| 783 return prepaintRect; | 847 return prepaintRect; |
| 784 } | 848 } |
| 785 | 849 |
| 786 } | 850 } |
| OLD | NEW |