Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(11)

Side by Side Diff: third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp

Issue 2714673002: [SPv2] Implement effect compositing for indirect reasons (Closed)
Patch Set: Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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 "platform/graphics/compositing/PaintArtifactCompositor.h" 5 #include "platform/graphics/compositing/PaintArtifactCompositor.h"
6 6
7 #include "cc/layers/content_layer_client.h" 7 #include "cc/layers/content_layer_client.h"
8 #include "cc/layers/layer.h" 8 #include "cc/layers/layer.h"
9 #include "cc/layers/picture_layer.h" 9 #include "cc/layers/picture_layer.h"
10 #include "cc/playback/compositing_display_item.h" 10 #include "cc/playback/compositing_display_item.h"
(...skipping 543 matching lines...) Expand 10 before | Expand all | Expand 10 after
554 ccInvalidationRect, 554 ccInvalidationRect,
555 rasterTracking ? &rasterTracking->trackedRasterInvalidations[index] 555 rasterTracking ? &rasterTracking->trackedRasterInvalidations[index]
556 : nullptr); 556 : nullptr);
557 } 557 }
558 } 558 }
559 559
560 newContentLayerClients.push_back(std::move(contentLayerClient)); 560 newContentLayerClients.push_back(std::move(contentLayerClient));
561 return ccPictureLayer; 561 return ccPictureLayer;
562 } 562 }
563 563
564 bool PaintArtifactCompositor::canMergeInto( 564 PaintArtifactCompositor::PendingLayer::PendingLayer(
565 const PaintArtifact& paintArtifact, 565 const PaintChunk& firstPaintChunk,
566 const PaintChunk& newChunk, 566 bool chunkIsForeign,
567 const PendingLayer& candidatePendingLayer) { 567 GeometryMapper& geometryMapper)
568 const PaintChunk& pendingLayerFirstChunk = 568 : bounds(firstPaintChunk.bounds),
569 *candidatePendingLayer.paintChunks[0]; 569 knownToBeOpaque(firstPaintChunk.knownToBeOpaque),
570 if (paintArtifact.getDisplayItemList()[newChunk.beginIndex].isForeignLayer()) 570 backfaceHidden(firstPaintChunk.properties.backfaceHidden),
571 return false; 571 propertyTreeState(firstPaintChunk.properties.propertyTreeState),
572 572 isForeign(chunkIsForeign) {
573 if (paintArtifact.getDisplayItemList()[pendingLayerFirstChunk.beginIndex] 573 paintChunks.push_back(&firstPaintChunk);
574 .isForeignLayer()) 574 }
575 return false; 575
576 576 void PaintArtifactCompositor::PendingLayer::merge(
577 if (newChunk.properties.backfaceHidden != 577 const PendingLayer& guest,
578 pendingLayerFirstChunk.properties.backfaceHidden)
579 return false;
580
581 DCHECK_GE(candidatePendingLayer.paintChunks.size(), 1u);
582 PropertyTreeStateIterator iterator(newChunk.properties.propertyTreeState);
583 for (const PropertyTreeState* currentState =
584 &newChunk.properties.propertyTreeState;
585 currentState; currentState = iterator.next()) {
586 if (*currentState == candidatePendingLayer.propertyTreeState)
587 return true;
588 if (currentState->hasDirectCompositingReasons())
589 return false;
590 }
591 return false;
592 }
593
594 bool PaintArtifactCompositor::mightOverlap(
595 const PaintChunk& paintChunk,
596 const PendingLayer& candidatePendingLayer,
597 GeometryMapper& geometryMapper) { 578 GeometryMapper& geometryMapper) {
579 DCHECK(!isForeign && !guest.isForeign);
580 DCHECK_EQ(backfaceHidden, guest.backfaceHidden);
581
582 paintChunks.appendVector(guest.paintChunks);
583 FloatRect oldBounds = bounds;
584 bounds.unite(geometryMapper
585 .localToAncestorVisualRect(
586 guest.bounds, guest.propertyTreeState, propertyTreeState)
587 .rect());
588 if (bounds != oldBounds)
589 knownToBeOpaque = false;
590 }
591
592 void PaintArtifactCompositor::PendingLayer::upcast(
593 const PropertyTreeState& newState,
594 GeometryMapper& geometryMapper) {
595 bounds = geometryMapper
596 .localToAncestorVisualRect(bounds, propertyTreeState, newState)
597 .rect();
598 propertyTreeState = newState;
599 // TODO(trchen): Upgrade GeometryMapper.
600 // knownToBeOpaque = knownToBeOpaque && enclosingRect(mappedRegion) ==
601 // enclosedRect(mappedRegion);
602 // localToAncestorVisualRect returns the enclosingRect of the mapped region.
603 // A variant that returns the enclosedRect is needed.
604 knownToBeOpaque = false;
605 }
606
607 #if 0
608 static unsigned nodeDepth(const TransformPaintPropertyNode* node) {
609 unsigned depth = 0;
610 while (node) {
611 depth++;
612 node = node->parent();
613 }
614 return depth;
615 }
616
617 // Return true if there are no direct compositing reason on the path between two transform nodes.
618 static bool transformsAreCompatible(const TransformPaintPropertyNode* nodeA, con st TransformPaintPropertyNode* nodeB) {
619 // Measure both depths.
620 unsigned depthA = nodeDepth(nodeA);
621 unsigned depthB = nodeDepth(nodeB);
622
623 // Make it so depthA >= depthB.
624 if (depthA < depthB) {
625 std::swap(nodeA, nodeB);
626 std::swap(depthA, depthB);
627 }
628
629 // Make it so depthA == depthB.
630 while (depthA > depthB) {
631 if (nodeA->hasDirectCompositingReasons())
632 return false;
633 nodeA = nodeA->parent();
634 depthA--;
635 }
636
637 // Walk up until we find the ancestor.
638 while (nodeA != nodeB) {
639 if (nodeA->hasDirectCompositingReasons() || nodeB->hasDirectCompositingReaso ns())
640 return false;
641 nodeA = nodeA->parent();
642 nodeB = nodeB->parent();
643 }
644 return true;
645 }
646 #else
647 static bool transformsAreCompatible(const TransformPaintPropertyNode* nodeA,
648 const TransformPaintPropertyNode* nodeB) {
649 for (; nodeB != nodeA; nodeB = nodeB->parent()) {
650 if (!nodeB || nodeB->hasDirectCompositingReasons())
651 return false;
652 }
653 return true;
654 }
655 #endif
656
657 static bool canUpcastTo(const PropertyTreeState& guest,
658 const PropertyTreeState& home) {
659 DCHECK_EQ(home.effect(), guest.effect());
660
661 for (const ClipPaintPropertyNode* currentClip = guest.clip();
662 currentClip != home.clip(); currentClip = currentClip->parent()) {
663 if (currentClip->hasDirectCompositingReasons())
664 return false;
665 if (!transformsAreCompatible(home.transform(),
666 currentClip->localTransformSpace()))
667 return false;
668 }
669
670 return transformsAreCompatible(home.transform(), guest.transform());
671 }
672
673 // Returns nullptr if 'ancestor' is not a strict ancestor of 'node'.
674 // Otherwise, return the child of 'ancestor' that is an ancestor of 'node' or
675 // 'node' itself.
676 static const EffectPaintPropertyNode* strictAncestorOf(
677 const EffectPaintPropertyNode* ancestor,
678 const EffectPaintPropertyNode* node) {
679 for (; node; node = node->parent()) {
680 if (node->parent() == ancestor)
681 return node;
682 }
683 return nullptr;
684 }
685
686 static bool mightOverlap(const PropertyTreeState& stateA,
687 const FloatRect& boundsA,
688 const PropertyTreeState& stateB,
689 const FloatRect& boundsB,
690 GeometryMapper& geometryMapper) {
598 PropertyTreeState rootPropertyTreeState(TransformPaintPropertyNode::root(), 691 PropertyTreeState rootPropertyTreeState(TransformPaintPropertyNode::root(),
599 ClipPaintPropertyNode::root(), 692 ClipPaintPropertyNode::root(),
600 EffectPaintPropertyNode::root()); 693 EffectPaintPropertyNode::root());
601 694
602 FloatRect paintChunkScreenVisualRect = 695 FloatRect screenVisualRectA =
603 geometryMapper 696 geometryMapper
604 .localToAncestorVisualRect(paintChunk.bounds, 697 .localToAncestorVisualRect(boundsA, stateA, rootPropertyTreeState)
605 paintChunk.properties.propertyTreeState,
606 rootPropertyTreeState)
607 .rect(); 698 .rect();
608 699
609 FloatRect pendingLayerScreenVisualRect = 700 FloatRect screenVisualRectB =
610 geometryMapper 701 geometryMapper
611 .localToAncestorVisualRect(candidatePendingLayer.bounds, 702 .localToAncestorVisualRect(boundsB, stateB, rootPropertyTreeState)
612 candidatePendingLayer.propertyTreeState,
613 rootPropertyTreeState)
614 .rect(); 703 .rect();
615 704
616 return paintChunkScreenVisualRect.intersects(pendingLayerScreenVisualRect); 705 return screenVisualRectA.intersects(screenVisualRectB);
617 } 706 }
618 707
619 PaintArtifactCompositor::PendingLayer::PendingLayer( 708 void PaintArtifactCompositor::layerizeGroup(
620 const PaintChunk& firstPaintChunk) 709 const PaintArtifact& paintArtifact,
621 : bounds(firstPaintChunk.bounds), 710 Vector<PendingLayer>& pendingLayers,
622 knownToBeOpaque(firstPaintChunk.knownToBeOpaque), 711 GeometryMapper& geometryMapper,
623 backfaceHidden(firstPaintChunk.properties.backfaceHidden), 712 const EffectPaintPropertyNode& currentGroup,
624 propertyTreeState(firstPaintChunk.properties.propertyTreeState) { 713 Vector<PaintChunk>::const_iterator& chunkIt) {
625 paintChunks.push_back(&firstPaintChunk); 714 size_t firstLayerInCurrentGroup = pendingLayers.size();
626 } 715 while (chunkIt != paintArtifact.paintChunks().end()) {
627 716 // Look at the effect node of the next chunk. There are 3 possible cases:
pdr. 2017/02/23 06:05:18 Do you have an intuition about the frequency of ea
trchen 2017/02/23 22:19:45 Case A and B always happen in pair, and should be
628 void PaintArtifactCompositor::PendingLayer::add( 717 // A. The next chunk does not belong to the current group.
629 const PaintChunk& paintChunk, 718 // B. The next chunk belongs to some subgroup of the current group.
630 GeometryMapper* geometryMapper) { 719 // C. The next chunk belongs to the current group but no subgroup.
631 DCHECK(paintChunk.properties.backfaceHidden == backfaceHidden); 720 const EffectPaintPropertyNode* chunkEffect =
632 paintChunks.push_back(&paintChunk); 721 chunkIt->properties.propertyTreeState.effect();
633 FloatRect mappedBounds = paintChunk.bounds; 722 if (chunkEffect != &currentGroup) {
634 if (geometryMapper) { 723 const EffectPaintPropertyNode* subgroup =
635 mappedBounds = geometryMapper->localToAncestorRect( 724 strictAncestorOf(&currentGroup, chunkEffect);
636 mappedBounds, paintChunk.properties.propertyTreeState.transform(), 725 // Case A: This means we need to close the current group without
637 propertyTreeState.transform()); 726 // processing the next chunk.
638 } 727 if (!subgroup)
639 bounds.unite(mappedBounds); 728 break;
640 if (bounds.size() != paintChunks[0]->bounds.size()) { 729 // Case B: The following chunks belong to a subgroup. Process them by
641 if (bounds.size() != paintChunk.bounds.size()) 730 // a recursion call.
642 knownToBeOpaque = false; 731 size_t firstLayerInSubgroup = pendingLayers.size();
643 else 732 layerizeGroup(paintArtifact, pendingLayers, geometryMapper, *subgroup,
644 knownToBeOpaque = paintChunk.knownToBeOpaque; 733 chunkIt);
734 // Now the chunk iterator stepped over the subgroup we just saw.
735 // If the subgroup generated 2 or more layers then the grouping must be
736 // composited as well.
737 if (pendingLayers.size() != firstLayerInSubgroup + 1)
738 continue;
739 // Attempt to "decomposite" subgroup. Only decomposite one level deep
740 // because the recusion should have decomposited the sub-subgroups.
741 // If we see a deep subgroup here, that implies some intermediate
742 // subgroup must be composited.
743 PendingLayer& subgroupLayer = pendingLayers[firstLayerInSubgroup];
744 if (subgroupLayer.propertyTreeState.effect() != subgroup)
745 continue;
746 // TODO(trchen): Exotic blending layer may be decomposited only if it
747 // could be merged into the first layer of the current group.
748 if (subgroup->blendMode() != SkBlendMode::kSrcOver)
749 continue;
750 if (subgroupLayer.isForeign)
751 continue;
752 if (subgroup->hasDirectCompositingReasons() ||
753 !canUpcastTo(subgroupLayer.propertyTreeState,
pdr. 2017/02/23 06:05:18 Can you add a note about the performance of this?
trchen 2017/02/23 22:19:45 Acknowledged.
754 PropertyTreeState(subgroup->localTransformSpace(),
755 subgroup->outputClip(), subgroup)))
756 continue;
757 subgroupLayer.upcast(
758 PropertyTreeState(subgroup->localTransformSpace(),
759 subgroup->outputClip(), &currentGroup),
760 geometryMapper);
761 } else {
762 // Case C: The next chunk belongs to the current group but no subgroup.
763 bool isForeign = paintArtifact.getDisplayItemList()[chunkIt->beginIndex]
764 .isForeignLayer();
765 pendingLayers.push_back(
766 PendingLayer(*chunkIt++, isForeign, geometryMapper));
767 if (isForeign)
768 continue;
769 }
770 // At this point pendingLayers.back() is the either a layer from a
771 // "decomposited" subgroup or a layer created from a chunk we just
772 // processed. Now determine whether it could be merged into a previous
773 // layer.
774 const PendingLayer& newLayer = pendingLayers.back();
775 DCHECK(!newLayer.isForeign);
776 DCHECK_EQ(&currentGroup, newLayer.propertyTreeState.effect());
777 // This iterates pendingLayers[firstLayerInCurrentGroup:-1] in reverse.
778 for (size_t candidateIndex = pendingLayers.size() - 1;
779 candidateIndex-- > firstLayerInCurrentGroup;) {
780 PendingLayer& candidateLayer = pendingLayers[candidateIndex];
781 if (!candidateLayer.isForeign &&
782 newLayer.backfaceHidden == candidateLayer.backfaceHidden &&
783 candidateLayer.propertyTreeState.effect() == &currentGroup &&
784 canUpcastTo(newLayer.propertyTreeState,
785 candidateLayer.propertyTreeState)) {
786 candidateLayer.merge(newLayer, geometryMapper);
787 pendingLayers.pop_back();
788 break;
789 }
790 if (mightOverlap(newLayer.propertyTreeState, newLayer.bounds,
791 candidateLayer.propertyTreeState, candidateLayer.bounds,
792 geometryMapper))
793 break;
794 }
645 } 795 }
646 } 796 }
647 797
648 void PaintArtifactCompositor::collectPendingLayers( 798 void PaintArtifactCompositor::collectPendingLayers(
649 const PaintArtifact& paintArtifact, 799 const PaintArtifact& paintArtifact,
650 Vector<PendingLayer>& pendingLayers, 800 Vector<PendingLayer>& pendingLayers,
651 GeometryMapper& geometryMapper) { 801 GeometryMapper& geometryMapper) {
652 // n = # of paint chunks. Memoizing canMergeInto() can get it to O(n^2), and 802 Vector<PaintChunk>::const_iterator cursor =
653 // other heuristics can make worst-case behavior better. 803 paintArtifact.paintChunks().begin();
654 for (const PaintChunk& paintChunk : paintArtifact.paintChunks()) { 804 layerizeGroup(paintArtifact, pendingLayers, geometryMapper,
655 bool createNew = true; 805 *EffectPaintPropertyNode::root(), cursor);
656 for (Vector<PendingLayer>::reverse_iterator candidatePendingLayer = 806 DCHECK_EQ(paintArtifact.paintChunks().end(), cursor);
657 pendingLayers.rbegin();
658 candidatePendingLayer != pendingLayers.rend();
659 ++candidatePendingLayer) {
660 if (canMergeInto(paintArtifact, paintChunk, *candidatePendingLayer)) {
661 candidatePendingLayer->add(paintChunk, &geometryMapper);
662 createNew = false;
663 break;
664 }
665 if (mightOverlap(paintChunk, *candidatePendingLayer, geometryMapper)) {
666 break;
667 }
668 }
669 if (createNew)
670 pendingLayers.push_back(PendingLayer(paintChunk));
671 }
672 } 807 }
673 808
674 void PaintArtifactCompositor::update( 809 void PaintArtifactCompositor::update(
675 const PaintArtifact& paintArtifact, 810 const PaintArtifact& paintArtifact,
676 RasterInvalidationTrackingMap<const PaintChunk>* rasterChunkInvalidations, 811 RasterInvalidationTrackingMap<const PaintChunk>* rasterChunkInvalidations,
677 bool storeDebugInfo, 812 bool storeDebugInfo,
678 GeometryMapper& geometryMapper) { 813 GeometryMapper& geometryMapper) {
679 #ifndef NDEBUG 814 #ifndef NDEBUG
680 storeDebugInfo = true; 815 storeDebugInfo = true;
681 #endif 816 #endif
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
747 #ifndef NDEBUG 882 #ifndef NDEBUG
748 void PaintArtifactCompositor::showDebugData() { 883 void PaintArtifactCompositor::showDebugData() {
749 LOG(ERROR) << layersAsJSON(LayerTreeIncludesDebugInfo) 884 LOG(ERROR) << layersAsJSON(LayerTreeIncludesDebugInfo)
750 ->toPrettyJSONString() 885 ->toPrettyJSONString()
751 .utf8() 886 .utf8()
752 .data(); 887 .data();
753 } 888 }
754 #endif 889 #endif
755 890
756 } // namespace blink 891 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698