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 |