diff options
author | Florin Malita <fmalita@chromium.org> | 2018-01-03 16:17:29 -0500 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-01-04 00:59:20 +0000 |
commit | c75e2401a82640c35b0b5f80a5684d0892904530 (patch) | |
tree | 0742a71071c9b92399a1182ec20ebfc69f8918f9 /experimental | |
parent | 5a59c26193272825e814b50f7d9856c1b122531f (diff) |
[sksg] Refine invalidation logic
We need to discriminate between nodes whose bounds updates contribute to the dirty
region, and nodes whose bounds changes do not.
E.g. animated shape in a group: the animated shape node bounds should yield damage,
but the ancestor group bounds should not.
To accomplish this, we refine the invalidation state:
1) self invalidation == the node itself was invalidated, and its bounds updates
yield damage.
2) descendant invalidation == the node has some (self-)invalidated descendant,
but its own bounds are not contributing damage.
Also:
* hoist the bounding box invalidation logic into the base class (Node::revalidate)
and update to respect the states described above.
* remove (now-redundant) GeometryNode bbox logic.
* update revalidation methods to return the node bbox instead of void
TBR=
Change-Id: I8023d1793fb501c945a53f2dc2d2983e5b620ade
Reviewed-on: https://skia-review.googlesource.com/90581
Reviewed-by: Florin Malita <fmalita@chromium.org>
Commit-Queue: Florin Malita <fmalita@chromium.org>
Diffstat (limited to 'experimental')
21 files changed, 147 insertions, 98 deletions
diff --git a/experimental/sksg/SkSGDraw.cpp b/experimental/sksg/SkSGDraw.cpp index fe6d42a152..c8e621856a 100644 --- a/experimental/sksg/SkSGDraw.cpp +++ b/experimental/sksg/SkSGDraw.cpp @@ -29,19 +29,14 @@ void Draw::onRender(SkCanvas* canvas) const { fGeometry->draw(canvas, fPaint->makePaint()); } -void Draw::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { - SkASSERT(this->isInvalidated()); +SkRect Draw::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { + SkASSERT(this->hasInval()); // TODO: paint bounds extents - const auto oldBounds = fGeometry->fBounds; - - fGeometry->revalidate(ic, ctm); + const auto bounds = fGeometry->revalidate(ic, ctm); fPaint->revalidate(ic, ctm); - ic->inval(oldBounds, ctm); - if (fGeometry->fBounds != oldBounds) { - ic->inval(fGeometry->fBounds, ctm); - } + return bounds; } } // namespace sksg diff --git a/experimental/sksg/SkSGDraw.h b/experimental/sksg/SkSGDraw.h index f5146dee28..20ead3d5f6 100644 --- a/experimental/sksg/SkSGDraw.h +++ b/experimental/sksg/SkSGDraw.h @@ -34,7 +34,7 @@ protected: void onRender(SkCanvas*) const override; - void onRevalidate(InvalidationController*, const SkMatrix&) override; + SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; private: sk_sp<GeometryNode> fGeometry; diff --git a/experimental/sksg/SkSGEffectNode.cpp b/experimental/sksg/SkSGEffectNode.cpp index c09bcf0955..1ecf7c7a92 100644 --- a/experimental/sksg/SkSGEffectNode.cpp +++ b/experimental/sksg/SkSGEffectNode.cpp @@ -22,8 +22,10 @@ void EffectNode::onRender(SkCanvas* canvas) const { fChild->render(canvas); } -void EffectNode::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { - fChild->revalidate(ic, ctm); +SkRect EffectNode::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { + SkASSERT(this->hasInval()); + + return fChild->revalidate(ic, ctm); } } // namespace sksg diff --git a/experimental/sksg/SkSGEffectNode.h b/experimental/sksg/SkSGEffectNode.h index b9a44a6cad..ab0968e96c 100644 --- a/experimental/sksg/SkSGEffectNode.h +++ b/experimental/sksg/SkSGEffectNode.h @@ -25,7 +25,7 @@ protected: void onRender(SkCanvas*) const override; - void onRevalidate(InvalidationController*, const SkMatrix&) override; + SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; private: sk_sp<RenderNode> fChild; diff --git a/experimental/sksg/SkSGGeometryNode.cpp b/experimental/sksg/SkSGGeometryNode.cpp index ffd5db4d1c..6ac7eda6a4 100644 --- a/experimental/sksg/SkSGGeometryNode.cpp +++ b/experimental/sksg/SkSGGeometryNode.cpp @@ -9,18 +9,9 @@ namespace sksg { -GeometryNode::GeometryNode() - : fBounds(SkRect::MakeLTRB(SK_ScalarMin, SK_ScalarMin, SK_ScalarMax, SK_ScalarMax)) {} - void GeometryNode::draw(SkCanvas* canvas, const SkPaint& paint) const { - SkASSERT(!this->isInvalidated()); + SkASSERT(!this->hasInval()); this->onDraw(canvas, paint); } -void GeometryNode::onRevalidate(InvalidationController*, const SkMatrix&) { - SkASSERT(this->isInvalidated()); - - fBounds = this->onComputeBounds(); -} - } // namespace sksg diff --git a/experimental/sksg/SkSGGeometryNode.h b/experimental/sksg/SkSGGeometryNode.h index a687b19aea..a43937510f 100644 --- a/experimental/sksg/SkSGGeometryNode.h +++ b/experimental/sksg/SkSGGeometryNode.h @@ -10,8 +10,6 @@ #include "SkSGNode.h" -#include "SkRect.h" - class SkCanvas; class SkPaint; @@ -30,21 +28,15 @@ public: // SkPath asPath() const; // unused for now protected: - GeometryNode(); + GeometryNode() = default; virtual void onDraw(SkCanvas*, const SkPaint&) const = 0; - virtual SkRect onComputeBounds() const = 0; - // virtual SkPath onAsPath() const = 0; // unused for now - void onRevalidate(InvalidationController*, const SkMatrix&) override; - private: friend class Draw; // wants to know the cached bounds. - SkRect fBounds; - typedef Node INHERITED; }; diff --git a/experimental/sksg/SkSGGroup.cpp b/experimental/sksg/SkSGGroup.cpp index b8e28f7286..fa9ae1e90e 100644 --- a/experimental/sksg/SkSGGroup.cpp +++ b/experimental/sksg/SkSGGroup.cpp @@ -27,6 +27,8 @@ void Group::addChild(sk_sp<RenderNode> node) { node->addInvalReceiver(this); fChildren.push_back(std::move(node)); + + this->invalidateSelf(); } void Group::removeChild(const sk_sp<RenderNode>& node) { @@ -39,6 +41,8 @@ void Group::removeChild(const sk_sp<RenderNode>& node) { } } SkASSERT(fChildren.count() == origCount - 1); + + this->invalidateSelf(); } void Group::onRender(SkCanvas* canvas) const { @@ -47,10 +51,16 @@ void Group::onRender(SkCanvas* canvas) const { } } -void Group::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { +SkRect Group::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { + SkASSERT(this->hasInval()); + + SkRect bounds = SkRect::MakeEmpty(); + for (const auto& child : fChildren) { - child->revalidate(ic, ctm); + bounds.join(child->revalidate(ic, ctm)); } + + return bounds; } } // namespace sksg diff --git a/experimental/sksg/SkSGGroup.h b/experimental/sksg/SkSGGroup.h index 2ed9d0ecb5..f9126ea37f 100644 --- a/experimental/sksg/SkSGGroup.h +++ b/experimental/sksg/SkSGGroup.h @@ -31,7 +31,7 @@ protected: ~Group() override; void onRender(SkCanvas*) const override; - void onRevalidate(InvalidationController*, const SkMatrix&) override; + SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; private: SkTArray<sk_sp<RenderNode>, true> fChildren; diff --git a/experimental/sksg/SkSGInvalidationController.cpp b/experimental/sksg/SkSGInvalidationController.cpp index 4b133d871b..81a3376bf6 100644 --- a/experimental/sksg/SkSGInvalidationController.cpp +++ b/experimental/sksg/SkSGInvalidationController.cpp @@ -12,9 +12,13 @@ namespace sksg { -InvalidationController::InvalidationController() {} +InvalidationController::InvalidationController() : fBounds(SkRect::MakeEmpty()) {} void InvalidationController::inval(const SkRect& r, const SkMatrix& ctm) { + if (r.isEmpty()) { + return; + } + SkTCopyOnFirstWrite<SkRect> rect(r); if (!ctm.isIdentity()) { @@ -22,6 +26,7 @@ void InvalidationController::inval(const SkRect& r, const SkMatrix& ctm) { } fRects.push(*rect); + fBounds.join(*rect); } } // namespace sksg diff --git a/experimental/sksg/SkSGInvalidationController.h b/experimental/sksg/SkSGInvalidationController.h index 4354d43129..df3857c1fe 100644 --- a/experimental/sksg/SkSGInvalidationController.h +++ b/experimental/sksg/SkSGInvalidationController.h @@ -27,11 +27,13 @@ public: void inval(const SkRect&, const SkMatrix& ctm = SkMatrix::I()); - const SkRect* begin() const { return fRects.begin(); } - const SkRect* end() const { return fRects.end(); } + const SkRect& bounds() const { return fBounds; } + const SkRect* begin() const { return fRects.begin(); } + const SkRect* end() const { return fRects.end(); } private: SkTDArray<SkRect> fRects; + SkRect fBounds; typedef SkNoncopyable INHERITED; }; diff --git a/experimental/sksg/SkSGNode.cpp b/experimental/sksg/SkSGNode.cpp index 3b404edd50..d3e804070c 100644 --- a/experimental/sksg/SkSGNode.cpp +++ b/experimental/sksg/SkSGNode.cpp @@ -7,34 +7,41 @@ #include "SkSGNode.h" +#include "SkSGInvalidationController.h" + namespace sksg { class Node::ScopedFlag { public: ScopedFlag(Node* node, uint32_t flag) : fNode(node) - , fFlag(flag) { - SkASSERT(!(fNode->fFlags & fFlag)); - fNode->fFlags |= fFlag; + , fFlag(flag) + , fWasSet(node->fFlags & flag) { + node->fFlags |= flag; } ~ScopedFlag() { - fNode->fFlags &= ~fFlag;; + if (!fWasSet) { + fNode->fFlags &= ~fFlag;; + } } + bool wasSet() const { return fWasSet; } + private: Node* fNode; uint32_t fFlag; + bool fWasSet; }; -#define TRAVERSAL_GUARD \ - if (this->fFlags & kInTraversal_Flag) { \ - return; \ - } \ - ScopedFlag traversal_guard(this, kInTraversal_Flag); +#define TRAVERSAL_GUARD \ + ScopedFlag traversal_guard(this, kInTraversal_Flag); \ + if (traversal_guard.wasSet()) \ + return Node::Node() : fInvalReceiver(nullptr) - , fFlags(kInvalidated_Flag) {} + , fBounds(SkRect::MakeLargestS32()) + , fFlags(kInvalSelf_Flag | kInvalDescendant_Flag) {} Node::~Node() { if (fFlags & kReceiverArray_Flag) { @@ -92,26 +99,51 @@ void Node::forEachInvalReceiver(Func&& func) const { } } -void Node::invalidate() { - TRAVERSAL_GUARD - - if (this->isInvalidated()) { +void Node::invalidateSelf() { + if (this->hasSelfInval()) { return; } - fFlags |= kInvalidated_Flag; + fFlags |= kInvalSelf_Flag; + this->invalidateAncestors(); +} + +void Node::invalidateAncestors() { + TRAVERSAL_GUARD; + forEachInvalReceiver([&](Node* receiver) { - receiver->invalidate(); + if (receiver->hasDescendantInval()) { + return; + } + receiver->fFlags |= kInvalDescendant_Flag; + receiver->invalidateAncestors(); }); } -void Node::revalidate(InvalidationController* ic, const SkMatrix& ctm) { - TRAVERSAL_GUARD +const SkRect& Node::revalidate(InvalidationController* ic, const SkMatrix& ctm) { + TRAVERSAL_GUARD fBounds; - if (this->isInvalidated()) { - this->onRevalidate(ic, ctm); - fFlags &= ~kInvalidated_Flag; + if (!this->hasInval()) { + return fBounds; } + + SkRect prevBounds; + if (this->hasSelfInval()) { + prevBounds = fBounds; + } + + fBounds = this->onRevalidate(ic, ctm); + + if (this->hasSelfInval()) { + ic->inval(prevBounds, ctm); + if (fBounds != prevBounds) { + ic->inval(fBounds, ctm); + } + } + + fFlags &= ~(kInvalSelf_Flag | kInvalDescendant_Flag); + + return fBounds; } } // namespace sksg diff --git a/experimental/sksg/SkSGNode.h b/experimental/sksg/SkSGNode.h index 30ff85d3c7..bc5970a3d9 100644 --- a/experimental/sksg/SkSGNode.h +++ b/experimental/sksg/SkSGNode.h @@ -8,6 +8,7 @@ #ifndef SkSGNode_DEFINED #define SkSGNode_DEFINED +#include "SkRect.h" #include "SkRefCnt.h" #include "SkTDArray.h" @@ -29,21 +30,24 @@ class InvalidationController; */ class Node : public SkRefCnt { public: - // Traverse the DAG and revalidate any connected/invalidated nodes. - void revalidate(InvalidationController*, const SkMatrix&); + // Traverse the DAG and revalidate any dependant/invalidated nodes. + // Returns the bounding box for the DAG fragment. + const SkRect& revalidate(InvalidationController*, const SkMatrix&); protected: Node(); ~Node() override; - // Mark this node and (transitively) any invalidation receivers for revalidation. - void invalidate(); + void invalidateSelf(); + void invalidateAncestors(); - bool isInvalidated() const { return fFlags & kInvalidated_Flag; } + bool hasSelfInval() const { return fFlags & kInvalSelf_Flag; } + bool hasDescendantInval() const { return fFlags & kInvalDescendant_Flag; } + bool hasInval() const { return this->hasSelfInval() || this->hasDescendantInval(); } - // Dispatched on revalidation. Subclasses are expected to recompute their geometry - // and push dirty rects to the InvalidationController. - virtual void onRevalidate(InvalidationController*, const SkMatrix& ctm) = 0; + // Dispatched on revalidation. Subclasses are expected to recompute/cache their properties + // and return their bounding box in local coordinates. + virtual SkRect onRevalidate(InvalidationController*, const SkMatrix& ctm) = 0; private: void addInvalReceiver(Node*); @@ -57,9 +61,10 @@ private: void forEachInvalReceiver(Func&&) const; enum Flags { - kInvalidated_Flag = 1 << 0, // the node requires revalidation - kReceiverArray_Flag = 1 << 1, // the node has more than one inval receiver - kInTraversal_Flag = 1 << 2, // the node is part of a traversal (cycle detection) + kInvalSelf_Flag = 1 << 0, // the node requires revalidation + kInvalDescendant_Flag = 1 << 1, // the node's descendents require invalidation + kReceiverArray_Flag = 1 << 2, // the node has more than one inval receiver + kInTraversal_Flag = 1 << 3, // the node is part of a traversal (cycle detection) }; class ScopedFlag; @@ -68,18 +73,19 @@ private: Node* fInvalReceiver; SkTDArray<Node*>* fInvalReceiverArray; }; + SkRect fBounds; uint32_t fFlags; typedef SkRefCnt INHERITED; }; // Helper for defining attribute getters/setters in subclasses. -#define SG_ATTRIBUTE(attr_name, attr_type, attr_container) \ +#define SG_ATTRIBUTE(attr_name, attr_type, attr_container) \ attr_type get##attr_name() const { return attr_container; } \ - void set##attr_name(attr_type v) { \ - if (attr_container == v) return; \ - attr_container = v; \ - this->invalidate(); \ + void set##attr_name(attr_type v) { \ + if (attr_container == v) return; \ + attr_container = v; \ + this->invalidateSelf(); \ } } // namespace sksg diff --git a/experimental/sksg/SkSGPaintNode.cpp b/experimental/sksg/SkSGPaintNode.cpp index 2b7a31fbad..fbdfae5d69 100644 --- a/experimental/sksg/SkSGPaintNode.cpp +++ b/experimental/sksg/SkSGPaintNode.cpp @@ -12,23 +12,27 @@ namespace sksg { PaintNode::PaintNode() {} const SkPaint& PaintNode::makePaint() { - SkASSERT(!this->isInvalidated()); + SkASSERT(!this->hasInval()); return fPaint; } -void PaintNode::onRevalidate(InvalidationController*, const SkMatrix&) { - SkASSERT(this->isInvalidated()); +SkRect PaintNode::onRevalidate(InvalidationController*, const SkMatrix&) { + SkASSERT(this->hasInval()); - fPaint.reset(); - fPaint.setAntiAlias(fAntiAlias); - fPaint.setStyle(fStyle); - fPaint.setStrokeWidth(fStrokeWidth); - fPaint.setStrokeMiter(fStrokeMiter); - fPaint.setStrokeJoin(fStrokeJoin); - fPaint.setStrokeCap(fStrokeCap); + if (this->hasSelfInval()) { + fPaint.reset(); + fPaint.setAntiAlias(fAntiAlias); + fPaint.setStyle(fStyle); + fPaint.setStrokeWidth(fStrokeWidth); + fPaint.setStrokeMiter(fStrokeMiter); + fPaint.setStrokeJoin(fStrokeJoin); + fPaint.setStrokeCap(fStrokeCap); - this->onApplyToPaint(&fPaint); + this->onApplyToPaint(&fPaint); + } + + return SkRect::MakeEmpty(); } } // namespace sksg diff --git a/experimental/sksg/SkSGPaintNode.h b/experimental/sksg/SkSGPaintNode.h index 534ad551ae..a2fbada065 100644 --- a/experimental/sksg/SkSGPaintNode.h +++ b/experimental/sksg/SkSGPaintNode.h @@ -36,7 +36,7 @@ protected: virtual void onApplyToPaint(SkPaint*) const = 0; - void onRevalidate(InvalidationController*, const SkMatrix&) override; + SkRect onRevalidate(InvalidationController*, const SkMatrix&) final; private: SkPaint fPaint; diff --git a/experimental/sksg/SkSGRenderNode.cpp b/experimental/sksg/SkSGRenderNode.cpp index 1609bac724..19e4d0ea5a 100644 --- a/experimental/sksg/SkSGRenderNode.cpp +++ b/experimental/sksg/SkSGRenderNode.cpp @@ -12,7 +12,7 @@ namespace sksg { RenderNode::RenderNode() {} void RenderNode::render(SkCanvas* canvas) const { - SkASSERT(!this->isInvalidated()); + SkASSERT(!this->hasInval()); this->onRender(canvas); } diff --git a/experimental/sksg/effects/SkSGTransform.cpp b/experimental/sksg/effects/SkSGTransform.cpp index ce83599871..ca4c5cd162 100644 --- a/experimental/sksg/effects/SkSGTransform.cpp +++ b/experimental/sksg/effects/SkSGTransform.cpp @@ -21,9 +21,13 @@ void Transform::onRender(SkCanvas* canvas) const { this->INHERITED::onRender(canvas); } -void Transform::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { - const auto localCTM = SkMatrix::Concat(ctm, fMatrix); - this->INHERITED::onRevalidate(ic, localCTM); +SkRect Transform::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { + SkASSERT(this->hasInval()); + + auto bounds = this->INHERITED::onRevalidate(ic, SkMatrix::Concat(ctm, fMatrix)); + fMatrix.mapRect(&bounds); + + return bounds; } } // namespace sksg diff --git a/experimental/sksg/effects/SkSGTransform.h b/experimental/sksg/effects/SkSGTransform.h index d7bc5d4fc8..a32f83dcc6 100644 --- a/experimental/sksg/effects/SkSGTransform.h +++ b/experimental/sksg/effects/SkSGTransform.h @@ -30,7 +30,7 @@ protected: void onRender(SkCanvas*) const override; - void onRevalidate(InvalidationController*, const SkMatrix&) override; + SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; private: SkMatrix fMatrix; diff --git a/experimental/sksg/geometry/SkSGPath.cpp b/experimental/sksg/geometry/SkSGPath.cpp index 8a1550a8f7..9b7b0427ea 100644 --- a/experimental/sksg/geometry/SkSGPath.cpp +++ b/experimental/sksg/geometry/SkSGPath.cpp @@ -18,7 +18,9 @@ void Path::onDraw(SkCanvas* canvas, const SkPaint& paint) const { canvas->drawPath(fPath, paint); } -SkRect Path::onComputeBounds() const { +SkRect Path::onRevalidate(InvalidationController*, const SkMatrix&) { + SkASSERT(this->hasSelfInval()); + return fPath.computeTightBounds(); } diff --git a/experimental/sksg/geometry/SkSGPath.h b/experimental/sksg/geometry/SkSGPath.h index 42c56188a2..52212cfc82 100644 --- a/experimental/sksg/geometry/SkSGPath.h +++ b/experimental/sksg/geometry/SkSGPath.h @@ -30,7 +30,7 @@ public: protected: void onDraw(SkCanvas*, const SkPaint&) const override; - SkRect onComputeBounds() const override; + SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; private: explicit Path(const SkPath&); diff --git a/experimental/sksg/geometry/SkSGRect.cpp b/experimental/sksg/geometry/SkSGRect.cpp index 53e6fba400..a49fcf1315 100644 --- a/experimental/sksg/geometry/SkSGRect.cpp +++ b/experimental/sksg/geometry/SkSGRect.cpp @@ -18,7 +18,9 @@ void Rect::onDraw(SkCanvas* canvas, const SkPaint& paint) const { canvas->drawRect(fRect, paint); } -SkRect Rect::onComputeBounds() const { +SkRect Rect::onRevalidate(InvalidationController*, const SkMatrix&) { + SkASSERT(this->hasSelfInval()); + return fRect; } @@ -28,7 +30,9 @@ void RRect::onDraw(SkCanvas* canvas, const SkPaint& paint) const { canvas->drawRRect(fRRect, paint); } -SkRect RRect::onComputeBounds() const { +SkRect RRect::onRevalidate(InvalidationController*, const SkMatrix&) { + SkASSERT(this->hasSelfInval()); + return fRRect.getBounds(); } diff --git a/experimental/sksg/geometry/SkSGRect.h b/experimental/sksg/geometry/SkSGRect.h index cc912f0ad0..108b1b2186 100644 --- a/experimental/sksg/geometry/SkSGRect.h +++ b/experimental/sksg/geometry/SkSGRect.h @@ -34,7 +34,7 @@ public: protected: void onDraw(SkCanvas*, const SkPaint&) const override; - SkRect onComputeBounds() const override; + SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; private: explicit Rect(const SkRect&); @@ -55,7 +55,7 @@ public: protected: void onDraw(SkCanvas*, const SkPaint&) const override; - SkRect onComputeBounds() const override; + SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; private: explicit RRect(const SkRRect&); |