[sksg] Refactor inval registration

... to avoid having too many Node friends.

TBR=
Change-Id: I8f8ff570d94ea48017935066a3d51cd8265ec120
Reviewed-on: https://skia-review.googlesource.com/97980
Reviewed-by: Florin Malita <fmalita@chromium.org>
Commit-Queue: Florin Malita <fmalita@chromium.org>
This commit is contained in:
Florin Malita 2018-01-22 10:19:28 -05:00 committed by Skia Commit-Bot
parent dba65f95e4
commit 3ba3fa72ae
10 changed files with 64 additions and 72 deletions

View File

@ -16,13 +16,13 @@ namespace sksg {
Draw::Draw(sk_sp<GeometryNode> geometry, sk_sp<PaintNode> paint)
: fGeometry(std::move(geometry))
, fPaint(std::move(paint)) {
fGeometry->addInvalReceiver(this);
fPaint->addInvalReceiver(this);
this->observeInval(fGeometry);
this->observeInval(fPaint);
}
Draw::~Draw() {
fGeometry->removeInvalReceiver(this);
fPaint->removeInvalReceiver(this);
this->unobserveInval(fGeometry);
this->unobserveInval(fPaint);
}
void Draw::onRender(SkCanvas* canvas) const {

View File

@ -11,11 +11,11 @@ namespace sksg {
EffectNode::EffectNode(sk_sp<RenderNode> child)
: fChild(std::move(child)) {
fChild->addInvalReceiver(this);
this->observeInval(fChild);
}
EffectNode::~EffectNode() {
fChild->removeInvalReceiver(this);
this->unobserveInval(fChild);
}
void EffectNode::onRender(SkCanvas* canvas) const {

View File

@ -13,7 +13,7 @@ Group::Group() {}
Group::~Group() {
for (const auto& child : fChildren) {
child->removeInvalReceiver(this);
this->unobserveInval(child);
}
}
@ -25,7 +25,7 @@ void Group::addChild(sk_sp<RenderNode> node) {
}
}
node->addInvalReceiver(this);
this->observeInval(node);
fChildren.push_back(std::move(node));
this->invalidate();
@ -36,7 +36,7 @@ void Group::removeChild(const sk_sp<RenderNode>& node) {
for (int i = 0; i < origCount; ++i) {
if (fChildren[i] == node) {
fChildren.removeShuffle(i);
node->removeInvalReceiver(this);
this->unobserveInval(node);
break;
}
}

View File

@ -39,64 +39,66 @@ private:
return
Node::Node(uint32_t invalTraits)
: fInvalReceiver(nullptr)
: fInvalObserver(nullptr)
, fBounds(SkRectPriv::MakeLargeS32())
, fInvalTraits(invalTraits)
, fFlags(kInvalidated_Flag) {}
Node::~Node() {
if (fFlags & kReceiverArray_Flag) {
SkASSERT(fInvalReceiverArray->isEmpty());
delete fInvalReceiverArray;
if (fFlags & kObserverArray_Flag) {
SkASSERT(fInvalObserverArray->isEmpty());
delete fInvalObserverArray;
} else {
SkASSERT(!fInvalReceiver);
SkASSERT(!fInvalObserver);
}
}
void Node::addInvalReceiver(Node* receiver) {
if (!(fFlags & kReceiverArray_Flag)) {
if (!fInvalReceiver) {
fInvalReceiver = receiver;
void Node::observeInval(const sk_sp<Node>& node) {
SkASSERT(node);
if (!(node->fFlags & kObserverArray_Flag)) {
if (!node->fInvalObserver) {
node->fInvalObserver = this;
return;
}
auto receivers = new SkTDArray<Node*>();
receivers->setReserve(2);
receivers->push(fInvalReceiver);
auto observers = new SkTDArray<Node*>();
observers->setReserve(2);
observers->push(node->fInvalObserver);
fInvalReceiverArray = receivers;
fFlags |= kReceiverArray_Flag;
node->fInvalObserverArray = observers;
node->fFlags |= kObserverArray_Flag;
}
// No duplicate receivers.
SkASSERT(fInvalReceiverArray->find(receiver) < 0);
// No duplicate observers.
SkASSERT(node->fInvalObserverArray->find(this) < 0);
fInvalReceiverArray->push(receiver);
node->fInvalObserverArray->push(this);
}
void Node::removeInvalReceiver(Node* receiver) {
if (!(fFlags & kReceiverArray_Flag)) {
SkASSERT(fInvalReceiver == receiver);
fInvalReceiver = nullptr;
void Node::unobserveInval(const sk_sp<Node>& node) {
SkASSERT(node);
if (!(node->fFlags & kObserverArray_Flag)) {
SkASSERT(node->fInvalObserver == this);
node->fInvalObserver = nullptr;
return;
}
const auto idx = fInvalReceiverArray->find(receiver);
const auto idx = node->fInvalObserverArray->find(this);
SkASSERT(idx >= 0);
fInvalReceiverArray->remove(idx);
node->fInvalObserverArray->remove(idx);
}
template <typename Func>
void Node::forEachInvalReceiver(Func&& func) const {
if (fFlags & kReceiverArray_Flag) {
for (const auto& parent : *fInvalReceiverArray) {
void Node::forEachInvalObserver(Func&& func) const {
if (fFlags & kObserverArray_Flag) {
for (const auto& parent : *fInvalObserverArray) {
func(parent);
}
return;
}
if (fInvalReceiver) {
func(fInvalReceiver);
if (fInvalObserver) {
func(fInvalObserver);
}
}
@ -109,15 +111,15 @@ void Node::invalidate(bool damageBubbling) {
}
if (damageBubbling && !(fInvalTraits & kBubbleDamage_Trait)) {
// Found a damage receiver.
// Found a damage observer.
fFlags |= kDamage_Flag;
damageBubbling = false;
}
fFlags |= kInvalidated_Flag;
forEachInvalReceiver([&](Node* receiver) {
receiver->invalidate(damageBubbling);
forEachInvalObserver([&](Node* observer) {
observer->invalidate(damageBubbling);
});
}

View File

@ -57,36 +57,26 @@ protected:
// and return their bounding box in local coordinates.
virtual SkRect onRevalidate(InvalidationController*, const SkMatrix& ctm) = 0;
// Register/unregister |this| to receive invalidation events from a descendant.
void observeInval(const sk_sp<Node>&);
void unobserveInval(const sk_sp<Node>&);
private:
enum Flags {
kInvalidated_Flag = 1 << 0, // the node or its descendants require revalidation
kDamage_Flag = 1 << 1, // the node contributes damage during revalidation
kReceiverArray_Flag = 1 << 2, // the node has more than one inval receiver
kObserverArray_Flag = 1 << 2, // the node has more than one inval observer
kInTraversal_Flag = 1 << 3, // the node is part of a traversal (cycle detection)
};
void addInvalReceiver(Node*);
void removeInvalReceiver(Node*);
// TODO: too friendly, find another way.
friend class Draw;
friend class EffectNode;
friend class GeometryTransform;
friend class Group;
friend class MaskEffect;
friend class Matrix;
friend class Merge;
friend class Stroke;
friend class Transform;
friend class TrimEffect;
template <typename Func>
void forEachInvalReceiver(Func&&) const;
void forEachInvalObserver(Func&&) const;
class ScopedFlag;
union {
Node* fInvalReceiver;
SkTDArray<Node*>* fInvalReceiverArray;
Node* fInvalObserver;
SkTDArray<Node*>* fInvalObserverArray;
};
SkRect fBounds;
const uint32_t fInvalTraits : 16;

View File

@ -14,11 +14,11 @@ namespace sksg {
MaskEffect::MaskEffect(sk_sp<RenderNode> child, sk_sp<RenderNode> mask)
: INHERITED(std::move(child))
, fMaskNode(std::move(mask)) {
fMaskNode->addInvalReceiver(this);
this->observeInval(fMaskNode);
}
MaskEffect::~MaskEffect() {
fMaskNode->removeInvalReceiver(this);
this->unobserveInval(fMaskNode);
}
void MaskEffect::onRender(SkCanvas* canvas) const {

View File

@ -16,13 +16,13 @@ Matrix::Matrix(const SkMatrix& m, sk_sp<Matrix> parent)
, fParent(std::move(parent))
, fLocalMatrix(m) {
if (fParent) {
fParent->addInvalReceiver(this);
this->observeInval(fParent);
}
}
Matrix::~Matrix() {
if (fParent) {
fParent->removeInvalReceiver(this);
this->unobserveInval(fParent);
}
}
@ -40,11 +40,11 @@ SkRect Matrix::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) {
Transform::Transform(sk_sp<RenderNode> child, sk_sp<Matrix> matrix)
: INHERITED(std::move(child))
, fMatrix(std::move(matrix)) {
fMatrix->addInvalReceiver(this);
this->observeInval(fMatrix);
}
Transform::~Transform() {
fMatrix->removeInvalReceiver(this);
this->unobserveInval(fMatrix);
}
void Transform::onRender(SkCanvas* canvas) const {

View File

@ -14,13 +14,13 @@ namespace sksg {
GeometryTransform::GeometryTransform(sk_sp<GeometryNode> child, sk_sp<Matrix> matrix)
: fChild(std::move(child))
, fMatrix(std::move(matrix)) {
fChild->addInvalReceiver(this);
fMatrix->addInvalReceiver(this);
this->observeInval(fChild);
this->observeInval(fMatrix);
}
GeometryTransform::~GeometryTransform() {
fChild->removeInvalReceiver(this);
fMatrix->removeInvalReceiver(this);
this->unobserveInval(fChild);
this->unobserveInval(fMatrix);
}
SkRect GeometryTransform::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) {

View File

@ -16,13 +16,13 @@ Merge::Merge(std::vector<sk_sp<GeometryNode>>&& geos, Mode mode)
: fGeos(std::move(geos))
, fMode(mode) {
for (const auto& geo : fGeos) {
geo->addInvalReceiver(this);
this->observeInval(geo);
}
}
Merge::~Merge() {
for (const auto& geo : fGeos) {
geo->removeInvalReceiver(this);
this->unobserveInval(geo);
}
}

View File

@ -15,11 +15,11 @@ namespace sksg {
TrimEffect::TrimEffect(sk_sp<GeometryNode> child)
: fChild(std::move(child)) {
fChild->addInvalReceiver(this);
this->observeInval(fChild);
}
TrimEffect::~TrimEffect() {
fChild->removeInvalReceiver(this);
this->unobserveInval(fChild);
}
// TODO