[skottie] Expose SG inval controller on seek()

- shift the revalidation phase from Scene::render() to Scene::animate()
 - pass an optional inval controller to Scene::animate() and Animation::seek()
 - hoist the showInval logic out of SkSG, into clients

This allows clients to track dirty regions and detect cases where no updates are needed.

Bug: skia:9267
Change-Id: I3d35bf58b6eee9bfeb6e127ba58e2b96713b772d
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/229001
Commit-Queue: Florin Malita <fmalita@chromium.org>
Reviewed-by: Mike Reed <reed@google.com>
This commit is contained in:
Florin Malita 2019-07-22 12:05:41 -04:00 committed by Skia Commit-Bot
parent 766b42b7ba
commit 00d4f535c9
10 changed files with 71 additions and 44 deletions

View File

@ -174,7 +174,9 @@ EMSCRIPTEN_BINDINGS(Skottie) {
}))
.function("size", &skottie::Animation::size)
.function("duration", &skottie::Animation::duration)
.function("seek", &skottie::Animation::seek)
.function("seek", optional_override([](skottie::Animation& self, SkScalar t)->void {
self.seek(t);
}))
.function("render", optional_override([](skottie::Animation& self, SkCanvas* canvas)->void {
self.render(canvas, nullptr);
}), allow_raw_pointers())

View File

@ -24,7 +24,12 @@ class SkStream;
namespace skjson { class ObjectValue; }
namespace sksg { class Scene; }
namespace sksg {
class InvalidationController;
class Scene;
} // namespace sksg
namespace skottie {
@ -213,14 +218,15 @@ public:
* Updates the animation state for |t|.
*
* @param t normalized [0..1] frame selector (0 -> first frame, 1 -> final frame)
* @param ic optional invalidation controller (dirty region tracking)
*
*/
void seek(SkScalar t);
void seek(SkScalar t, sksg::InvalidationController* ic = nullptr);
/** Update the animation state to match t, specifed in frame time
* i.e. relative to duration().
*/
void seekFrameTime(double t);
void seekFrameTime(double t, sksg::InvalidationController* = nullptr);
/**
* Returns the animation duration in seconds.
@ -230,8 +236,6 @@ public:
const SkString& version() const { return fVersion; }
const SkSize& size() const { return fSize; }
void setShowInval(bool show);
private:
enum Flags : uint32_t {
kRequiresTopLevelIsolation = 1 << 0, // Needs to draw into a layer due to layer blending.

View File

@ -558,12 +558,6 @@ Animation::Animation(std::unique_ptr<sksg::Scene> scene, SkString version, const
Animation::~Animation() = default;
void Animation::setShowInval(bool show) {
if (fScene) {
fScene->setShowInval(show);
}
}
void Animation::render(SkCanvas* canvas, const SkRect* dstR) const {
this->render(canvas, dstR, 0);
}
@ -593,7 +587,7 @@ void Animation::render(SkCanvas* canvas, const SkRect* dstR, RenderFlags renderF
fScene->render(canvas);
}
void Animation::seek(SkScalar t) {
void Animation::seek(SkScalar t, sksg::InvalidationController* ic) {
TRACE_EVENT0("skottie", TRACE_FUNC);
if (!fScene)
@ -602,12 +596,12 @@ void Animation::seek(SkScalar t) {
// Per AE/Lottie semantics out_point is exclusive.
const auto kLastValidFrame = std::nextafter(fOutPoint, fInPoint);
fScene->animate(SkTPin(fInPoint + t * (fOutPoint - fInPoint), fInPoint, kLastValidFrame));
fScene->animate(SkTPin(fInPoint + t * (fOutPoint - fInPoint), fInPoint, kLastValidFrame), ic);
}
void Animation::seekFrameTime(double t) {
void Animation::seekFrameTime(double t, sksg::InvalidationController* ic) {
if (double dur = this->duration()) {
this->seek((SkScalar)(t / dur));
this->seek((SkScalar)(t / dur), ic);
}
}

View File

@ -33,6 +33,8 @@ public:
const SkRect* begin() const { return fRects.begin(); }
const SkRect* end() const { return fRects.end(); }
void reset();
private:
SkTDArray<SkRect> fRects;
SkRect fBounds;

View File

@ -19,6 +19,7 @@ struct SkPoint;
namespace sksg {
class InvalidationController;
class RenderNode;
/**
@ -67,18 +68,14 @@ public:
Scene& operator=(const Scene&) = delete;
void render(SkCanvas*) const;
void animate(float t);
void animate(float t, InvalidationController* = nullptr);
const RenderNode* nodeAt(const SkPoint&) const;
void setShowInval(bool show) { fShowInval = show; }
private:
Scene(sk_sp<RenderNode> root, AnimatorList&& animators);
const sk_sp<RenderNode> fRoot;
const AnimatorList fAnimators;
bool fShowInval = false;
};
} // namespace sksg

View File

@ -5,6 +5,7 @@
* found in the LICENSE file.
*/
#include "include/core/SkCanvas.h"
#include "include/core/SkRRect.h"
#include "include/utils/SkRandom.h"
#include "samplecode/Sample.h"
@ -12,6 +13,7 @@
#include "modules/sksg/include/SkSGDraw.h"
#include "modules/sksg/include/SkSGGroup.h"
#include "modules/sksg/include/SkSGInvalidationController.h"
#include "modules/sksg/include/SkSGPaint.h"
#include "modules/sksg/include/SkSGPath.h"
#include "modules/sksg/include/SkSGRect.h"
@ -162,7 +164,6 @@ protected:
return true;
case 'I':
fShowInval = !fShowInval;
fScene->setShowInval(fShowInval);
return true;
default:
break;
@ -182,7 +183,23 @@ protected:
}
void onDrawContent(SkCanvas* canvas) override {
sksg::InvalidationController ic;
fScene->animate(0, &ic);
fScene->render(canvas);
if (fShowInval) {
SkPaint fill, stroke;
fill.setAntiAlias(true);
fill.setColor(0x40ff0000);
stroke.setAntiAlias(true);
stroke.setColor(0xffff0000);
stroke.setStyle(SkPaint::kStroke_Style);
for (const auto& r : ic) {
canvas->drawRect(r, fill);
canvas->drawRect(r, stroke);
}
}
}
bool onAnimate(double nanos) override {

View File

@ -29,4 +29,9 @@ void InvalidationController::inval(const SkRect& r, const SkMatrix& ctm) {
fBounds.join(*rect);
}
void InvalidationController::reset() {
fRects.reset();
fBounds.setEmpty();
}
} // namespace sksg

View File

@ -42,31 +42,18 @@ Scene::Scene(sk_sp<RenderNode> root, AnimatorList&& animators)
Scene::~Scene() = default;
void Scene::render(SkCanvas* canvas) const {
// TODO: externalize the inval controller.
// TODO: relocate the revalidation to tick()?
InvalidationController ic;
fRoot->revalidate(fShowInval ? &ic : nullptr, SkMatrix::I());
// Ensure the SG is revalidated.
// Note: this is a no-op if the scene has already been revalidated - e.g. in animate().
fRoot->revalidate(nullptr, SkMatrix::I());
fRoot->render(canvas);
if (fShowInval) {
SkPaint fill, stroke;
fill.setAntiAlias(true);
fill.setColor(0x40ff0000);
stroke.setAntiAlias(true);
stroke.setColor(0xffff0000);
stroke.setStyle(SkPaint::kStroke_Style);
for (const auto& r : ic) {
canvas->drawRect(r, fill);
canvas->drawRect(r, stroke);
}
}
}
void Scene::animate(float t) {
void Scene::animate(float t, InvalidationController* ic) {
for (const auto& anim : fAnimators) {
anim->tick(t);
}
fRoot->revalidate(ic, SkMatrix::I());
}
const RenderNode* Scene::nodeAt(const SkPoint& p) const {

View File

@ -104,7 +104,6 @@ void SkottieSlide::load(SkScalar w, SkScalar h) {
fTimeBase = 0; // force a time reset
if (fAnimation) {
fAnimation->setShowInval(fShowAnimationInval);
SkDebugf("Loaded Bodymovin animation v: %s, size: [%f %f]\n",
fAnimation->version().c_str(),
fAnimation->size().width(),
@ -133,6 +132,24 @@ void SkottieSlide::draw(SkCanvas* canvas) {
if (fShowAnimationStats) {
draw_stats_box(canvas, fAnimationStats);
}
if (fShowAnimationInval) {
const auto t = SkMatrix::MakeRectToRect(SkRect::MakeSize(fAnimation->size()),
dstR,
SkMatrix::kCenter_ScaleToFit);
SkPaint fill, stroke;
fill.setAntiAlias(true);
fill.setColor(0x40ff0000);
stroke.setAntiAlias(true);
stroke.setColor(0xffff0000);
stroke.setStyle(SkPaint::kStroke_Style);
for (const auto& r : fInvalController) {
SkRect bounds;
t.mapRect(&bounds, r);
canvas->drawRect(bounds, fill);
canvas->drawRect(bounds, stroke);
}
}
}
}
@ -144,9 +161,10 @@ bool SkottieSlide::animate(double nanos) {
}
if (fAnimation) {
fInvalController.reset();
const auto t = msec - fTimeBase;
const auto d = fAnimation->duration() * 1000;
fAnimation->seek(std::fmod(t, d) / d);
fAnimation->seek(std::fmod(t, d) / d, &fInvalController);
}
return true;
}
@ -168,7 +186,6 @@ bool SkottieSlide::onMouse(SkScalar x, SkScalar y, InputState state, ModifierKey
case InputState::kUp:
fShowAnimationInval = !fShowAnimationInval;
fShowAnimationStats = !fShowAnimationStats;
fAnimation->setShowInval(fShowAnimationInval);
break;
default:
break;

View File

@ -12,6 +12,7 @@
#if defined(SK_ENABLE_SKOTTIE)
#include "modules/skottie/include/Skottie.h"
#include "modules/sksg/include/SkSGInvalidationController.h"
namespace sksg { class Scene; }
@ -35,6 +36,7 @@ private:
SkString fPath;
sk_sp<skottie::Animation> fAnimation;
skottie::Animation::Builder::Stats fAnimationStats;
sksg::InvalidationController fInvalController;
SkSize fWinSize = SkSize::MakeEmpty();
SkMSec fTimeBase = 0;
bool fShowAnimationInval = false,