Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 117f0c28 authored by Leon Scroggins III's avatar Leon Scroggins III Committed by android-build-merger
Browse files

Merge "AnimatedImageDrawable: Eliminate unnecessary calls to redraw" into pi-dev am: a2113aa4

am: 6353ff5b

Change-Id: I5258721b49834aba58e9bf19162e6a4588f68f0f
parents 15c6708f 6353ff5b
Loading
Loading
Loading
Loading
+0 −6
Original line number Original line Diff line number Diff line
@@ -239,11 +239,6 @@ static jlong AnimatedImageDrawable_nNativeByteSize(JNIEnv* env, jobject /*clazz*
    return drawable->byteSize();
    return drawable->byteSize();
}
}


static void AnimatedImageDrawable_nMarkInvisible(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
    auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
    drawable->markInvisible();
}

static void AnimatedImageDrawable_nSetMirrored(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
static void AnimatedImageDrawable_nSetMirrored(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
                                               jboolean mirrored) {
                                               jboolean mirrored) {
    auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
    auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
@@ -264,7 +259,6 @@ static const JNINativeMethod gAnimatedImageDrawableMethods[] = {
    { "nSetRepeatCount",     "(JI)V",                                                        (void*) AnimatedImageDrawable_nSetRepeatCount },
    { "nSetRepeatCount",     "(JI)V",                                                        (void*) AnimatedImageDrawable_nSetRepeatCount },
    { "nSetOnAnimationEndListener", "(JLandroid/graphics/drawable/AnimatedImageDrawable;)V", (void*) AnimatedImageDrawable_nSetOnAnimationEndListener },
    { "nSetOnAnimationEndListener", "(JLandroid/graphics/drawable/AnimatedImageDrawable;)V", (void*) AnimatedImageDrawable_nSetOnAnimationEndListener },
    { "nNativeByteSize",     "(J)J",                                                         (void*) AnimatedImageDrawable_nNativeByteSize },
    { "nNativeByteSize",     "(J)J",                                                         (void*) AnimatedImageDrawable_nNativeByteSize },
    { "nMarkInvisible",      "(J)V",                                                         (void*) AnimatedImageDrawable_nMarkInvisible },
    { "nSetMirrored",        "(JZ)V",                                                        (void*) AnimatedImageDrawable_nSetMirrored },
    { "nSetMirrored",        "(JZ)V",                                                        (void*) AnimatedImageDrawable_nSetMirrored },
};
};


+2 −20
Original line number Original line Diff line number Diff line
@@ -31,6 +31,7 @@ import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Handler;
import android.os.Looper;
import android.os.Looper;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.util.TypedValue;
@@ -348,7 +349,7 @@ public class AnimatedImageDrawable extends Drawable implements Animatable2 {
            if (mRunnable == null) {
            if (mRunnable == null) {
                mRunnable = this::invalidateSelf;
                mRunnable = this::invalidateSelf;
            }
            }
            scheduleSelf(mRunnable, nextUpdate);
            scheduleSelf(mRunnable, nextUpdate + SystemClock.uptimeMillis());
        } else if (nextUpdate == FINISHED) {
        } else if (nextUpdate == FINISHED) {
            // This means the animation was drawn in software mode and ended.
            // This means the animation was drawn in software mode and ended.
            postOnAnimationEnd();
            postOnAnimationEnd();
@@ -430,23 +431,6 @@ public class AnimatedImageDrawable extends Drawable implements Animatable2 {
        return mState.mAutoMirrored;
        return mState.mAutoMirrored;
    }
    }


    @Override
    public boolean setVisible(boolean visible, boolean restart) {
        if (!super.setVisible(visible, restart)) {
            return false;
        }

        if (mState.mNativePtr == 0) {
            throw new IllegalStateException("called setVisible on empty AnimatedImageDrawable");
        }

        if (!visible) {
            nMarkInvisible(mState.mNativePtr);
        }

        return true;
    }

    // Animatable overrides
    // Animatable overrides
    /**
    /**
     *  Return whether the animation is currently running.
     *  Return whether the animation is currently running.
@@ -616,7 +600,5 @@ public class AnimatedImageDrawable extends Drawable implements Animatable2 {
    @FastNative
    @FastNative
    private static native long nNativeByteSize(long nativePtr);
    private static native long nNativeByteSize(long nativePtr);
    @FastNative
    @FastNative
    private static native void nMarkInvisible(long nativePtr);
    @FastNative
    private static native void nSetMirrored(long nativePtr, boolean mirror);
    private static native void nSetMirrored(long nativePtr, boolean mirror);
}
}
+6 −0
Original line number Original line Diff line number Diff line
@@ -108,6 +108,12 @@ public:
        // *OR* will post itself for the next vsync automatically, use this
        // *OR* will post itself for the next vsync automatically, use this
        // only to avoid calling draw()
        // only to avoid calling draw()
        bool canDrawThisFrame = true;
        bool canDrawThisFrame = true;
        // Sentinel for animatedImageDelay meaning there is no need to post such
        // a message.
        static constexpr nsecs_t kNoAnimatedImageDelay = -1;
        // This is used to post a message to redraw when it is time to draw the
        // next frame of an AnimatedImageDrawable.
        nsecs_t animatedImageDelay = kNoAnimatedImageDelay;
    } out;
    } out;


    // This flag helps to disable projection for receiver nodes that do not have any backward
    // This flag helps to disable projection for receiver nodes that do not have any backward
+47 −36
Original line number Original line Diff line number Diff line
@@ -22,13 +22,12 @@
#include <SkPicture.h>
#include <SkPicture.h>
#include <SkRefCnt.h>
#include <SkRefCnt.h>
#include <SkTLazy.h>
#include <SkTLazy.h>
#include <SkTime.h>


namespace android {
namespace android {


AnimatedImageDrawable::AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage, size_t bytesUsed)
AnimatedImageDrawable::AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage, size_t bytesUsed)
        : mSkAnimatedImage(std::move(animatedImage)), mBytesUsed(bytesUsed) {
        : mSkAnimatedImage(std::move(animatedImage)), mBytesUsed(bytesUsed) {
    mTimeToShowNextSnapshot = mSkAnimatedImage->currentFrameDuration();
    mTimeToShowNextSnapshot = ms2ns(mSkAnimatedImage->currentFrameDuration());
}
}


void AnimatedImageDrawable::syncProperties() {
void AnimatedImageDrawable::syncProperties() {
@@ -62,28 +61,42 @@ bool AnimatedImageDrawable::nextSnapshotReady() const {
}
}


// Only called on the RenderThread while UI thread is locked.
// Only called on the RenderThread while UI thread is locked.
bool AnimatedImageDrawable::isDirty() {
bool AnimatedImageDrawable::isDirty(nsecs_t* outDelay) {
    const double currentTime = SkTime::GetMSecs();
    *outDelay = 0;
    const double lastWallTime = mLastWallTime;
    const nsecs_t currentTime = systemTime(CLOCK_MONOTONIC);
    const nsecs_t lastWallTime = mLastWallTime;


    mLastWallTime = currentTime;
    mLastWallTime = currentTime;
    if (!mRunning) {
    if (!mRunning) {
        mDidDraw = false;
        return false;
        return false;
    }
    }


    std::unique_lock lock{mSwapLock};
    std::unique_lock lock{mSwapLock};
    if (mDidDraw) {
    mCurrentTime += currentTime - lastWallTime;
    mCurrentTime += currentTime - lastWallTime;
        mDidDraw = false;
    }


    if (!mNextSnapshot.valid()) {
    if (!mNextSnapshot.valid()) {
        // Need to trigger onDraw in order to start decoding the next frame.
        // Need to trigger onDraw in order to start decoding the next frame.
        *outDelay = mTimeToShowNextSnapshot - mCurrentTime;
        return true;
        return true;
    }
    }


    return nextSnapshotReady() && mCurrentTime >= mTimeToShowNextSnapshot;
    if (mTimeToShowNextSnapshot > mCurrentTime) {
        *outDelay = mTimeToShowNextSnapshot - mCurrentTime;
    } else if (nextSnapshotReady()) {
        // We have not yet updated mTimeToShowNextSnapshot. Read frame duration
        // directly from mSkAnimatedImage.
        lock.unlock();
        std::unique_lock imageLock{mImageLock};
        *outDelay = ms2ns(mSkAnimatedImage->currentFrameDuration());
        return true;
    } else {
        // The next snapshot has not yet been decoded, but we've already passed
        // time to draw it. There's not a good way to know when decoding will
        // finish, so request an update immediately.
        *outDelay = 0;
    }

    return false;
}
}


// Only called on the AnimatedImageThread.
// Only called on the AnimatedImageThread.
@@ -91,7 +104,7 @@ AnimatedImageDrawable::Snapshot AnimatedImageDrawable::decodeNextFrame() {
    Snapshot snap;
    Snapshot snap;
    {
    {
        std::unique_lock lock{mImageLock};
        std::unique_lock lock{mImageLock};
        snap.mDuration = mSkAnimatedImage->decodeNextFrame();
        snap.mDurationMS = mSkAnimatedImage->decodeNextFrame();
        snap.mPic.reset(mSkAnimatedImage->newPictureSnapshot());
        snap.mPic.reset(mSkAnimatedImage->newPictureSnapshot());
    }
    }


@@ -105,7 +118,7 @@ AnimatedImageDrawable::Snapshot AnimatedImageDrawable::reset() {
        std::unique_lock lock{mImageLock};
        std::unique_lock lock{mImageLock};
        mSkAnimatedImage->reset();
        mSkAnimatedImage->reset();
        snap.mPic.reset(mSkAnimatedImage->newPictureSnapshot());
        snap.mPic.reset(mSkAnimatedImage->newPictureSnapshot());
        snap.mDuration = mSkAnimatedImage->currentFrameDuration();
        snap.mDurationMS = mSkAnimatedImage->currentFrameDuration();
    }
    }


    return snap;
    return snap;
@@ -127,8 +140,6 @@ void AnimatedImageDrawable::onDraw(SkCanvas* canvas) {
        canvas->scale(-1, 1);
        canvas->scale(-1, 1);
    }
    }


    mDidDraw = true;

    const bool starting = mStarting;
    const bool starting = mStarting;
    mStarting = false;
    mStarting = false;


@@ -157,12 +168,12 @@ void AnimatedImageDrawable::onDraw(SkCanvas* canvas) {
        std::unique_lock lock{mSwapLock};
        std::unique_lock lock{mSwapLock};
        if (mCurrentTime >= mTimeToShowNextSnapshot) {
        if (mCurrentTime >= mTimeToShowNextSnapshot) {
            mSnapshot = mNextSnapshot.get();
            mSnapshot = mNextSnapshot.get();
            const double timeToShowCurrentSnap = mTimeToShowNextSnapshot;
            const nsecs_t timeToShowCurrentSnap = mTimeToShowNextSnapshot;
            if (mSnapshot.mDuration == SkAnimatedImage::kFinished) {
            if (mSnapshot.mDurationMS == SkAnimatedImage::kFinished) {
                finalFrame = true;
                finalFrame = true;
                mRunning = false;
                mRunning = false;
            } else {
            } else {
                mTimeToShowNextSnapshot += mSnapshot.mDuration;
                mTimeToShowNextSnapshot += ms2ns(mSnapshot.mDurationMS);
                if (mCurrentTime >= mTimeToShowNextSnapshot) {
                if (mCurrentTime >= mTimeToShowNextSnapshot) {
                    // This would mean showing the current frame very briefly. It's
                    // This would mean showing the current frame very briefly. It's
                    // possible that not being displayed for a time resulted in
                    // possible that not being displayed for a time resulted in
@@ -192,7 +203,7 @@ void AnimatedImageDrawable::onDraw(SkCanvas* canvas) {
    }
    }
}
}


double AnimatedImageDrawable::drawStaging(SkCanvas* canvas) {
int AnimatedImageDrawable::drawStaging(SkCanvas* canvas) {
    SkAutoCanvasRestore acr(canvas, false);
    SkAutoCanvasRestore acr(canvas, false);
    if (mStagingProperties.mAlpha != SK_AlphaOPAQUE || mStagingProperties.mColorFilter.get()) {
    if (mStagingProperties.mAlpha != SK_AlphaOPAQUE || mStagingProperties.mColorFilter.get()) {
        SkPaint paint;
        SkPaint paint;
@@ -211,69 +222,69 @@ double AnimatedImageDrawable::drawStaging(SkCanvas* canvas) {
        // to redraw.
        // to redraw.
        std::unique_lock lock{mImageLock};
        std::unique_lock lock{mImageLock};
        canvas->drawDrawable(mSkAnimatedImage.get());
        canvas->drawDrawable(mSkAnimatedImage.get());
        return 0.0;
        return 0;
    }
    }


    if (mStarting) {
    if (mStarting) {
        mStarting = false;
        mStarting = false;
        double duration = 0.0;
        int durationMS = 0;
        {
        {
            std::unique_lock lock{mImageLock};
            std::unique_lock lock{mImageLock};
            mSkAnimatedImage->reset();
            mSkAnimatedImage->reset();
            duration = mSkAnimatedImage->currentFrameDuration();
            durationMS = mSkAnimatedImage->currentFrameDuration();
        }
        }
        {
        {
            std::unique_lock lock{mSwapLock};
            std::unique_lock lock{mSwapLock};
            mLastWallTime = 0.0;
            mLastWallTime = 0;
            mTimeToShowNextSnapshot = duration;
            // The current time will be added later, below.
            mTimeToShowNextSnapshot = ms2ns(durationMS);
        }
        }
    }
    }


    bool update = false;
    bool update = false;
    {
    {
        const double currentTime = SkTime::GetMSecs();
        const nsecs_t currentTime = systemTime(CLOCK_MONOTONIC);
        std::unique_lock lock{mSwapLock};
        std::unique_lock lock{mSwapLock};
        // mLastWallTime starts off at 0. If it is still 0, just update it to
        // mLastWallTime starts off at 0. If it is still 0, just update it to
        // the current time and avoid updating
        // the current time and avoid updating
        if (mLastWallTime == 0.0) {
        if (mLastWallTime == 0) {
            mCurrentTime = currentTime;
            mCurrentTime = currentTime;
            // mTimeToShowNextSnapshot is already set to the duration of the
            // mTimeToShowNextSnapshot is already set to the duration of the
            // first frame.
            // first frame.
            mTimeToShowNextSnapshot += currentTime;
            mTimeToShowNextSnapshot += currentTime;
        } else if (mRunning && mDidDraw) {
        } else if (mRunning) {
            mCurrentTime += currentTime - mLastWallTime;
            mCurrentTime += currentTime - mLastWallTime;
            update = mCurrentTime >= mTimeToShowNextSnapshot;
            update = mCurrentTime >= mTimeToShowNextSnapshot;
        }
        }
        mLastWallTime = currentTime;
        mLastWallTime = currentTime;
    }
    }


    double duration = 0.0;
    int durationMS = 0;
    {
    {
        std::unique_lock lock{mImageLock};
        std::unique_lock lock{mImageLock};
        if (update) {
        if (update) {
            duration = mSkAnimatedImage->decodeNextFrame();
            durationMS = mSkAnimatedImage->decodeNextFrame();
        }
        }


        canvas->drawDrawable(mSkAnimatedImage.get());
        canvas->drawDrawable(mSkAnimatedImage.get());
    }
    }


    mDidDraw = true;

    std::unique_lock lock{mSwapLock};
    std::unique_lock lock{mSwapLock};
    if (update) {
    if (update) {
        if (duration == SkAnimatedImage::kFinished) {
        if (durationMS == SkAnimatedImage::kFinished) {
            mRunning = false;
            mRunning = false;
            return duration;
            return SkAnimatedImage::kFinished;
        }
        }


        const double timeToShowCurrentSnapshot = mTimeToShowNextSnapshot;
        const nsecs_t timeToShowCurrentSnapshot = mTimeToShowNextSnapshot;
        mTimeToShowNextSnapshot += duration;
        mTimeToShowNextSnapshot += ms2ns(durationMS);
        if (mCurrentTime >= mTimeToShowNextSnapshot) {
        if (mCurrentTime >= mTimeToShowNextSnapshot) {
            // As in onDraw, prevent speedy catch-up behavior.
            // As in onDraw, prevent speedy catch-up behavior.
            mCurrentTime = timeToShowCurrentSnapshot;
            mCurrentTime = timeToShowCurrentSnapshot;
        }
        }
    }
    }
    return mTimeToShowNextSnapshot;

    return ns2ms(mTimeToShowNextSnapshot - mCurrentTime);
}
}


}  // namespace android
}  // namespace android
+14 −13
Original line number Original line Diff line number Diff line
@@ -19,6 +19,7 @@
#include <cutils/compiler.h>
#include <cutils/compiler.h>
#include <utils/Macros.h>
#include <utils/Macros.h>
#include <utils/RefBase.h>
#include <utils/RefBase.h>
#include <utils/Timers.h>


#include <SkAnimatedImage.h>
#include <SkAnimatedImage.h>
#include <SkCanvas.h>
#include <SkCanvas.h>
@@ -50,12 +51,15 @@ public:
    AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage, size_t bytesUsed);
    AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage, size_t bytesUsed);


    /**
    /**
     * This updates the internal time and returns true if the animation needs
     * This updates the internal time and returns true if the image needs
     * to be redrawn.
     * to be redrawn this frame.
     *
     *
     * This is called on RenderThread, while the UI thread is locked.
     * This is called on RenderThread, while the UI thread is locked.
     *
     * @param outDelay Nanoseconds in the future when the following frame
     *      will need to be drawn. 0 if not running.
     */
     */
    bool isDirty();
    bool isDirty(nsecs_t* outDelay);


    int getStagingAlpha() const { return mStagingProperties.mAlpha; }
    int getStagingAlpha() const { return mStagingProperties.mAlpha; }
    void setStagingAlpha(int alpha) { mStagingProperties.mAlpha = alpha; }
    void setStagingAlpha(int alpha) { mStagingProperties.mAlpha = alpha; }
@@ -68,7 +72,9 @@ public:
    virtual SkRect onGetBounds() override { return mSkAnimatedImage->getBounds(); }
    virtual SkRect onGetBounds() override { return mSkAnimatedImage->getBounds(); }


    // Draw to software canvas, and return time to next draw.
    // Draw to software canvas, and return time to next draw.
    double drawStaging(SkCanvas* canvas);
    // 0 means the animation is not running.
    // -1 means the animation advanced to the final frame.
    int drawStaging(SkCanvas* canvas);


    // Returns true if the animation was started; false otherwise (e.g. it was
    // Returns true if the animation was started; false otherwise (e.g. it was
    // already running)
    // already running)
@@ -84,11 +90,9 @@ public:
        mEndListener = std::move(listener);
        mEndListener = std::move(listener);
    }
    }


    void markInvisible() { mDidDraw = false; }

    struct Snapshot {
    struct Snapshot {
        sk_sp<SkPicture> mPic;
        sk_sp<SkPicture> mPic;
        int mDuration;
        int mDurationMS;


        Snapshot() = default;
        Snapshot() = default;


@@ -122,16 +126,13 @@ private:
    bool nextSnapshotReady() const;
    bool nextSnapshotReady() const;


    // When to switch from mSnapshot to mNextSnapshot.
    // When to switch from mSnapshot to mNextSnapshot.
    double mTimeToShowNextSnapshot = 0.0;
    nsecs_t mTimeToShowNextSnapshot = 0;


    // The current time for the drawable itself.
    // The current time for the drawable itself.
    double mCurrentTime = 0.0;
    nsecs_t mCurrentTime = 0;


    // The wall clock of the last time we called isDirty.
    // The wall clock of the last time we called isDirty.
    double mLastWallTime = 0.0;
    nsecs_t mLastWallTime = 0;

    // Whether we drew since the last call to isDirty.
    bool mDidDraw = false;


    // Locked when assigning snapshots and times. Operations while this is held
    // Locked when assigning snapshots and times. Operations while this is held
    // should be short.
    // should be short.
Loading