diff options
| author | 2018-02-06 16:21:50 -0500 | |
|---|---|---|
| committer | 2018-02-09 16:31:25 -0500 | |
| commit | d935157f48525d5fe7cc107c2d7aed99564b60bd (patch) | |
| tree | a6f45b3bb20ee9eb38ffe3cbdd6ab0bbe36ee08d | |
| parent | a5ffafbfda3b5f6dd7f883045b6b0da0556b934c (diff) | |
Fix AnimatedImageDrawable drawn in software
Test: Manual, existing CTS, I4e884636801c0a2e920ca9d99f3c38fb034b3774
- Fix a bug where the animation never advanced.
- Rename mFinished to mStarting. It was already being used to indicate
that we were restarting anyway. Now only set it to true in calls to
start().
- Prevent skipping ahead the same way we do in hardware.
- Return kFinished when reaching the last frame of the animation.
This also includes a fix for hardware drawing. The first time start() is
called, there is no need to create a snapshot of the first frame. Just
draw the first frame directly and kick off a decode of the second frame.
Change-Id: I0a6fb909a361dd4c233cfa2d79bc2210d2dcddc8
| -rw-r--r-- | libs/hwui/hwui/AnimatedImageDrawable.cpp | 76 | ||||
| -rw-r--r-- | libs/hwui/hwui/AnimatedImageDrawable.h | 2 |
2 files changed, 48 insertions, 30 deletions
diff --git a/libs/hwui/hwui/AnimatedImageDrawable.cpp b/libs/hwui/hwui/AnimatedImageDrawable.cpp index 2bded9b3a2d8..7e4f755643bc 100644 --- a/libs/hwui/hwui/AnimatedImageDrawable.cpp +++ b/libs/hwui/hwui/AnimatedImageDrawable.cpp @@ -41,8 +41,7 @@ bool AnimatedImageDrawable::start() { return false; } - // This will trigger a reset. - mFinished = true; + mStarting = true; mRunning = true; return true; @@ -125,8 +124,11 @@ void AnimatedImageDrawable::onDraw(SkCanvas* canvas) { mDidDraw = true; - bool drewDirectly = false; - if (!mSnapshot.mPic) { + const bool starting = mStarting; + mStarting = false; + + const bool drawDirectly = !mSnapshot.mPic; + if (drawDirectly) { // The image is not animating, and never was. Draw directly from // mSkAnimatedImage. SkAutoCanvasRestore acr(canvas, false); @@ -136,13 +138,14 @@ void AnimatedImageDrawable::onDraw(SkCanvas* canvas) { std::unique_lock lock{mImageLock}; mSkAnimatedImage->draw(canvas); - drewDirectly = true; - } - - if (mRunning && mFinished) { + if (!mRunning) { + return; + } + } else if (starting) { + // The image has animated, and now is being reset. Queue up the first + // frame, but keep showing the current frame until the first is ready. auto& thread = uirenderer::AnimatedImageThread::getInstance(); mNextSnapshot = thread.reset(sk_ref_sp(this)); - mFinished = false; } bool finalFrame = false; @@ -154,7 +157,6 @@ void AnimatedImageDrawable::onDraw(SkCanvas* canvas) { if (mSnapshot.mDuration == SkAnimatedImage::kFinished) { finalFrame = true; mRunning = false; - mFinished = true; } else { mTimeToShowNextSnapshot += mSnapshot.mDuration; if (mCurrentTime >= mTimeToShowNextSnapshot) { @@ -173,7 +175,7 @@ void AnimatedImageDrawable::onDraw(SkCanvas* canvas) { mNextSnapshot = thread.decodeNextFrame(sk_ref_sp(this)); } - if (!drewDirectly) { + if (!drawDirectly) { // No other thread will modify mCurrentSnap so this should be safe to // use without locking. canvas->drawPicture(mSnapshot.mPic, nullptr, lazyPaint.getMaybeNull()); @@ -195,14 +197,29 @@ double AnimatedImageDrawable::drawStaging(SkCanvas* canvas) { canvas->saveLayer(mSkAnimatedImage->getBounds(), &paint); } - if (mFinished && !mRunning) { - // Continue drawing the last frame, and return 0 to indicate no need to - // redraw. + if (!mRunning) { + // Continue drawing the current frame, and return 0 to indicate no need + // to redraw. std::unique_lock lock{mImageLock}; canvas->drawDrawable(mSkAnimatedImage.get()); return 0.0; } + if (mStarting) { + mStarting = false; + double duration = 0.0; + { + std::unique_lock lock{mImageLock}; + mSkAnimatedImage->reset(); + duration = mSkAnimatedImage->currentFrameDuration(); + } + { + std::unique_lock lock{mSwapLock}; + mLastWallTime = 0.0; + mTimeToShowNextSnapshot = duration; + } + } + bool update = false; { const double currentTime = SkTime::GetMSecs(); @@ -211,18 +228,12 @@ double AnimatedImageDrawable::drawStaging(SkCanvas* canvas) { // the current time and avoid updating if (mLastWallTime == 0.0) { mCurrentTime = currentTime; - } else if (mRunning) { - if (mFinished) { - mCurrentTime = currentTime; - { - std::unique_lock lock{mImageLock}; - mSkAnimatedImage->reset(); - } - mTimeToShowNextSnapshot = currentTime + mSkAnimatedImage->currentFrameDuration(); - } else { - mCurrentTime += currentTime - mLastWallTime; - update = mCurrentTime >= mTimeToShowNextSnapshot; - } + // mTimeToShowNextSnapshot is already set to the duration of the + // first frame. + mTimeToShowNextSnapshot += currentTime; + } else if (mRunning && mDidDraw) { + mCurrentTime += currentTime - mLastWallTime; + update = mCurrentTime >= mTimeToShowNextSnapshot; } mLastWallTime = currentTime; } @@ -237,13 +248,20 @@ double AnimatedImageDrawable::drawStaging(SkCanvas* canvas) { canvas->drawDrawable(mSkAnimatedImage.get()); } + mDidDraw = true; + std::unique_lock lock{mSwapLock}; if (update) { if (duration == SkAnimatedImage::kFinished) { mRunning = false; - mFinished = true; - } else { - mTimeToShowNextSnapshot += duration; + return duration; + } + + const double timeToShowCurrentSnapshot = mTimeToShowNextSnapshot; + mTimeToShowNextSnapshot += duration; + if (mCurrentTime >= mTimeToShowNextSnapshot) { + // As in onDraw, prevent speedy catch-up behavior. + mCurrentTime = timeToShowCurrentSnapshot; } } return mTimeToShowNextSnapshot; diff --git a/libs/hwui/hwui/AnimatedImageDrawable.h b/libs/hwui/hwui/AnimatedImageDrawable.h index 2fd6f40b71b5..07469d288787 100644 --- a/libs/hwui/hwui/AnimatedImageDrawable.h +++ b/libs/hwui/hwui/AnimatedImageDrawable.h @@ -102,7 +102,7 @@ protected: private: sk_sp<SkAnimatedImage> mSkAnimatedImage; bool mRunning = false; - bool mFinished = false; + bool mStarting = false; // A snapshot of the current frame to draw. Snapshot mSnapshot; |