[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:
parent
766b42b7ba
commit
00d4f535c9
@ -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())
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user