[skottie] Fix motion blur asserts
MotionBlurEffect makes use of many abilities some consider to be unnatural. Notably, it mutates the state of its subtree at render time (gasp) to sample various time points. Mutation triggers scene graph invalidation, which bubbles up the ancestor chain. While we immediately revalidate the subtree, we cannot do the same for ancestors (no full scene knowledge). This means post-rendering, we leave some SG nodes dirty - which triggers various debug asserts). The easiest fix is to temporarily suppress invalidation bubbling at the MotionBlurEffect node level (this is safe, because we always revalidate the subtree). Also add a post-render assert for tighter state validation. Change-Id: I376b7a8880f71d85e595c419334b42bc4720ac65 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/243420 Reviewed-by: Mike Klein <mtklein@google.com> Commit-Queue: Florin Malita <fmalita@chromium.org>
This commit is contained in:
parent
ee11283a0c
commit
0f11e115d7
@ -17,6 +17,23 @@
|
|||||||
namespace skottie {
|
namespace skottie {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
|
class MotionBlurEffect::AutoInvalBlocker {
|
||||||
|
public:
|
||||||
|
AutoInvalBlocker(const MotionBlurEffect* mb, const sk_sp<RenderNode>& child)
|
||||||
|
: fMBNode(const_cast<MotionBlurEffect*>(mb))
|
||||||
|
, fChild(child) {
|
||||||
|
fMBNode->unobserveInval(fChild);
|
||||||
|
}
|
||||||
|
|
||||||
|
~AutoInvalBlocker() {
|
||||||
|
fMBNode->observeInval(fChild);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
MotionBlurEffect* fMBNode;
|
||||||
|
const sk_sp<RenderNode>& fChild;
|
||||||
|
};
|
||||||
|
|
||||||
sk_sp<MotionBlurEffect> MotionBlurEffect::Make(sk_sp<sksg::Animator> animator,
|
sk_sp<MotionBlurEffect> MotionBlurEffect::Make(sk_sp<sksg::Animator> animator,
|
||||||
sk_sp<sksg::RenderNode> child,
|
sk_sp<sksg::RenderNode> child,
|
||||||
size_t samples_per_frame,
|
size_t samples_per_frame,
|
||||||
@ -188,6 +205,10 @@ void MotionBlurEffect::onRender(SkCanvas* canvas, const RenderContext* ctx) cons
|
|||||||
SkASSERT(this->children().size() == 1ul);
|
SkASSERT(this->children().size() == 1ul);
|
||||||
const auto& child = this->children()[0];
|
const auto& child = this->children()[0];
|
||||||
|
|
||||||
|
// We're about to mutate/revalidate the subtree for sampling. Capture the invalidation
|
||||||
|
// at this scope, to prevent dirtying ancestor SG nodes (no way to revalidate the global scene).
|
||||||
|
AutoInvalBlocker aib(this, child);
|
||||||
|
|
||||||
SkPixmap pm;
|
SkPixmap pm;
|
||||||
if (canvas->peekPixels(&pm) && (canvas->imageInfo().colorType() == kRGBA_8888_SkColorType ||
|
if (canvas->peekPixels(&pm) && (canvas->imageInfo().colorType() == kRGBA_8888_SkColorType ||
|
||||||
canvas->imageInfo().colorType() == kBGRA_8888_SkColorType )
|
canvas->imageInfo().colorType() == kBGRA_8888_SkColorType )
|
||||||
|
@ -24,6 +24,8 @@ public:
|
|||||||
SG_ATTRIBUTE(T, float, fT)
|
SG_ATTRIBUTE(T, float, fT)
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
class AutoInvalBlocker;
|
||||||
|
|
||||||
const RenderNode* onNodeAt(const SkPoint&) const override;
|
const RenderNode* onNodeAt(const SkPoint&) const override;
|
||||||
|
|
||||||
SkRect onRevalidate(sksg::InvalidationController* ic, const SkMatrix& ctm) override;
|
SkRect onRevalidate(sksg::InvalidationController* ic, const SkMatrix& ctm) override;
|
||||||
|
@ -43,6 +43,7 @@ void RenderNode::render(SkCanvas* canvas, const RenderContext* ctx) const {
|
|||||||
if (this->isVisible() && !this->bounds().isEmpty()) {
|
if (this->isVisible() && !this->bounds().isEmpty()) {
|
||||||
this->onRender(canvas, ctx);
|
this->onRender(canvas, ctx);
|
||||||
}
|
}
|
||||||
|
SkASSERT(!this->hasInval());
|
||||||
}
|
}
|
||||||
|
|
||||||
const RenderNode* RenderNode::nodeAt(const SkPoint& p) const {
|
const RenderNode* RenderNode::nodeAt(const SkPoint& p) const {
|
||||||
|
Loading…
Reference in New Issue
Block a user