diff options
| author | 2018-01-24 15:45:08 +0000 | |
|---|---|---|
| committer | 2018-01-24 15:45:08 +0000 | |
| commit | 08a45549af12d725b8df34f504bcc876b1a3cd28 (patch) | |
| tree | 541fb5266a6ded41b84a40efa3dbd9373a95bd55 | |
| parent | df64ef9be42b55e94b8da1f4b41acbd75bdd475f (diff) | |
| parent | 2d14213849d6df70d0fa80319ab4ffc08743a683 (diff) | |
Merge "Initial implmentation of AnimatedImageDrawables on the RenderThread."
| -rw-r--r-- | core/jni/android/graphics/AnimatedImageDrawable.cpp | 39 | ||||
| -rw-r--r-- | graphics/java/android/graphics/drawable/AnimatedImageDrawable.java | 18 | ||||
| -rw-r--r-- | libs/hwui/Android.bp | 1 | ||||
| -rw-r--r-- | libs/hwui/RecordingCanvas.cpp | 4 | ||||
| -rw-r--r-- | libs/hwui/RecordingCanvas.h | 3 | ||||
| -rw-r--r-- | libs/hwui/SkiaCanvas.cpp | 14 | ||||
| -rw-r--r-- | libs/hwui/SkiaCanvas.h | 3 | ||||
| -rw-r--r-- | libs/hwui/hwui/AnimatedImageDrawable.cpp | 152 | ||||
| -rw-r--r-- | libs/hwui/hwui/AnimatedImageDrawable.h | 91 | ||||
| -rw-r--r-- | libs/hwui/hwui/Canvas.h | 4 | ||||
| -rw-r--r-- | libs/hwui/pipeline/skia/SkiaDisplayList.cpp | 16 | ||||
| -rw-r--r-- | libs/hwui/pipeline/skia/SkiaDisplayList.h | 2 | ||||
| -rw-r--r-- | libs/hwui/pipeline/skia/SkiaPipeline.cpp | 10 | ||||
| -rw-r--r-- | libs/hwui/pipeline/skia/SkiaPipeline.h | 12 | ||||
| -rw-r--r-- | libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp | 6 | ||||
| -rw-r--r-- | libs/hwui/pipeline/skia/SkiaRecordingCanvas.h | 1 |
16 files changed, 330 insertions, 46 deletions
diff --git a/core/jni/android/graphics/AnimatedImageDrawable.cpp b/core/jni/android/graphics/AnimatedImageDrawable.cpp index ec15cce1f1d5..8b3ce663fae6 100644 --- a/core/jni/android/graphics/AnimatedImageDrawable.cpp +++ b/core/jni/android/graphics/AnimatedImageDrawable.cpp @@ -18,6 +18,7 @@ #include "ImageDecoder.h" #include "core_jni_helpers.h" +#include <hwui/AnimatedImageDrawable.h> #include <hwui/Canvas.h> #include <SkAndroidCodec.h> #include <SkAnimatedImage.h> @@ -27,10 +28,6 @@ using namespace android; -struct AnimatedImageDrawable { - sk_sp<SkAnimatedImage> mDrawable; - SkPaint mPaint; -}; // Note: jpostProcess holds a handle to the ImageDecoder. static jlong AnimatedImageDrawable_nCreate(JNIEnv* env, jobject /*clazz*/, @@ -65,20 +62,22 @@ static jlong AnimatedImageDrawable_nCreate(JNIEnv* env, jobject /*clazz*/, picture = recorder.finishRecordingAsPicture(); } - std::unique_ptr<AnimatedImageDrawable> drawable(new AnimatedImageDrawable); - drawable->mDrawable = SkAnimatedImage::Make(std::move(imageDecoder->mCodec), - scaledSize, subset, std::move(picture)); - if (!drawable->mDrawable) { + + sk_sp<SkAnimatedImage> animatedImg = SkAnimatedImage::Make(std::move(imageDecoder->mCodec), + scaledSize, subset, + std::move(picture)); + if (!animatedImg) { doThrowIOE(env, "Failed to create drawable"); return 0; } - drawable->mDrawable->start(); + sk_sp<AnimatedImageDrawable> drawable(new AnimatedImageDrawable(animatedImg)); + drawable->start(); return reinterpret_cast<jlong>(drawable.release()); } static void AnimatedImageDrawable_destruct(AnimatedImageDrawable* drawable) { - delete drawable; + SkSafeUnref(drawable); } static jlong AnimatedImageDrawable_nGetNativeFinalizer(JNIEnv* /*env*/, jobject /*clazz*/) { @@ -86,45 +85,43 @@ static jlong AnimatedImageDrawable_nGetNativeFinalizer(JNIEnv* /*env*/, jobject } static jlong AnimatedImageDrawable_nDraw(JNIEnv* env, jobject /*clazz*/, jlong nativePtr, - jlong canvasPtr, jlong msecs) { + jlong canvasPtr) { auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr); - double timeToNextUpdate = drawable->mDrawable->update(msecs); auto* canvas = reinterpret_cast<Canvas*>(canvasPtr); - canvas->drawAnimatedImage(drawable->mDrawable.get(), 0, 0, &drawable->mPaint); - return (jlong) timeToNextUpdate; + return (jlong) canvas->drawAnimatedImage(drawable); } static void AnimatedImageDrawable_nSetAlpha(JNIEnv* env, jobject /*clazz*/, jlong nativePtr, jint alpha) { auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr); - drawable->mPaint.setAlpha(alpha); + drawable->setStagingAlpha(alpha); } static jlong AnimatedImageDrawable_nGetAlpha(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) { auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr); - return drawable->mPaint.getAlpha(); + return drawable->getStagingAlpha(); } static void AnimatedImageDrawable_nSetColorFilter(JNIEnv* env, jobject /*clazz*/, jlong nativePtr, jlong nativeFilter) { auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr); auto* filter = reinterpret_cast<SkColorFilter*>(nativeFilter); - drawable->mPaint.setColorFilter(sk_ref_sp(filter)); + drawable->setStagingColorFilter(sk_ref_sp(filter)); } static jboolean AnimatedImageDrawable_nIsRunning(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) { auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr); - return drawable->mDrawable->isRunning(); + return drawable->isRunning(); } static void AnimatedImageDrawable_nStart(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) { auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr); - drawable->mDrawable->start(); + drawable->start(); } static void AnimatedImageDrawable_nStop(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) { auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr); - drawable->mDrawable->stop(); + drawable->stop(); } static long AnimatedImageDrawable_nNativeByteSize(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) { @@ -136,7 +133,7 @@ static long AnimatedImageDrawable_nNativeByteSize(JNIEnv* env, jobject /*clazz*/ static const JNINativeMethod gAnimatedImageDrawableMethods[] = { { "nCreate", "(JLandroid/graphics/ImageDecoder;IILandroid/graphics/Rect;)J", (void*) AnimatedImageDrawable_nCreate }, { "nGetNativeFinalizer", "()J", (void*) AnimatedImageDrawable_nGetNativeFinalizer }, - { "nDraw", "(JJJ)J", (void*) AnimatedImageDrawable_nDraw }, + { "nDraw", "(JJ)J", (void*) AnimatedImageDrawable_nDraw }, { "nSetAlpha", "(JI)V", (void*) AnimatedImageDrawable_nSetAlpha }, { "nGetAlpha", "(J)I", (void*) AnimatedImageDrawable_nGetAlpha }, { "nSetColorFilter", "(JJ)V", (void*) AnimatedImageDrawable_nSetColorFilter }, diff --git a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java index da170c0fae24..6d3ddd5c2c28 100644 --- a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java @@ -118,9 +118,12 @@ public class AnimatedImageDrawable extends Drawable implements Animatable { @Override public void draw(@NonNull Canvas canvas) { - long nextUpdate = nDraw(mNativePtr, canvas.getNativeCanvasWrapper(), - SystemClock.uptimeMillis()); - scheduleSelf(mRunnable, nextUpdate); + long nextUpdate = nDraw(mNativePtr, canvas.getNativeCanvasWrapper()); + // a value <= 0 indicates that the drawable is stopped or that renderThread + // will manage the animation + if (nextUpdate > 0) { + scheduleSelf(mRunnable, nextUpdate); + } } @Override @@ -130,6 +133,7 @@ public class AnimatedImageDrawable extends Drawable implements Animatable { + " 255! provided " + alpha); } nSetAlpha(mNativePtr, alpha); + invalidateSelf(); } @Override @@ -141,6 +145,7 @@ public class AnimatedImageDrawable extends Drawable implements Animatable { public void setColorFilter(@Nullable ColorFilter colorFilter) { long nativeFilter = colorFilter == null ? 0 : colorFilter.getNativeInstance(); nSetColorFilter(mNativePtr, nativeFilter); + invalidateSelf(); } @Override @@ -161,7 +166,10 @@ public class AnimatedImageDrawable extends Drawable implements Animatable { @Override public void start() { - nStart(mNativePtr); + if (isRunning() == false) { + nStart(mNativePtr); + invalidateSelf(); + } } @Override @@ -173,7 +181,7 @@ public class AnimatedImageDrawable extends Drawable implements Animatable { @Nullable ImageDecoder decoder, int width, int height, Rect cropRect) throws IOException; private static native long nGetNativeFinalizer(); - private static native long nDraw(long nativePtr, long canvasNativePtr, long msecs); + private static native long nDraw(long nativePtr, long canvasNativePtr); private static native void nSetAlpha(long nativePtr, int alpha); private static native int nGetAlpha(long nativePtr); private static native void nSetColorFilter(long nativePtr, long nativeFilter); diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index 7cacaf6a16ad..17f9b7cd62fc 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -137,6 +137,7 @@ cc_defaults { whole_static_libs: ["libskia"], srcs: [ + "hwui/AnimatedImageDrawable.cpp", "hwui/Bitmap.cpp", "font/CacheTexture.cpp", "font/Font.cpp", diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp index fb7b24623568..e1df1e7725b5 100644 --- a/libs/hwui/RecordingCanvas.cpp +++ b/libs/hwui/RecordingCanvas.cpp @@ -495,9 +495,9 @@ void RecordingCanvas::drawNinePatch(Bitmap& bitmap, const android::Res_png_9patc refPaint(paint), refBitmap(bitmap), refPatch(&patch))); } -void RecordingCanvas::drawAnimatedImage(SkAnimatedImage*, float left, float top, - const SkPaint*) { +double RecordingCanvas::drawAnimatedImage(AnimatedImageDrawable*) { // Unimplemented + return 0; } // Text diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h index dd06ada9da3d..e663402a80f3 100644 --- a/libs/hwui/RecordingCanvas.h +++ b/libs/hwui/RecordingCanvas.h @@ -183,8 +183,7 @@ public: virtual void drawNinePatch(Bitmap& bitmap, const android::Res_png_9patch& chunk, float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) override; - virtual void drawAnimatedImage(SkAnimatedImage*, float left, float top, - const SkPaint* paint) override; + virtual double drawAnimatedImage(AnimatedImageDrawable*) override; // Text virtual bool drawTextAbsolutePos() const override { return false; } diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp index dc274cf50a52..b2edd3392873 100644 --- a/libs/hwui/SkiaCanvas.cpp +++ b/libs/hwui/SkiaCanvas.cpp @@ -725,18 +725,8 @@ void SkiaCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk, floa mCanvas->drawImageLattice(image.get(), lattice, dst, addFilter(paint, &tmpPaint, colorFilter)); } -void SkiaCanvas::drawAnimatedImage(SkAnimatedImage* image, float left, float top, - const SkPaint* paint) { - sk_sp<SkPicture> pic(image->newPictureSnapshot()); - SkMatrix matrixStorage; - SkMatrix* matrix; - if (left == 0.0f && top == 0.0f) { - matrix = nullptr; - } else { - matrixStorage = SkMatrix::MakeTrans(left, top); - matrix = &matrixStorage; - } - mCanvas->drawPicture(pic.get(), matrix, paint); +double SkiaCanvas::drawAnimatedImage(AnimatedImageDrawable* imgDrawable) { + return imgDrawable->drawStaging(mCanvas); } void SkiaCanvas::drawVectorDrawable(VectorDrawableRoot* vectorDrawable) { diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h index 7137210406fb..3efc22a03cdf 100644 --- a/libs/hwui/SkiaCanvas.h +++ b/libs/hwui/SkiaCanvas.h @@ -124,8 +124,7 @@ public: virtual void drawNinePatch(Bitmap& bitmap, const android::Res_png_9patch& chunk, float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) override; - virtual void drawAnimatedImage(SkAnimatedImage*, float left, float top, - const SkPaint* paint) override; + virtual double drawAnimatedImage(AnimatedImageDrawable* imgDrawable) override; virtual bool drawTextAbsolutePos() const override { return true; } virtual void drawVectorDrawable(VectorDrawableRoot* vectorDrawable) override; diff --git a/libs/hwui/hwui/AnimatedImageDrawable.cpp b/libs/hwui/hwui/AnimatedImageDrawable.cpp new file mode 100644 index 000000000000..36dd06f2fce9 --- /dev/null +++ b/libs/hwui/hwui/AnimatedImageDrawable.cpp @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "AnimatedImageDrawable.h" + +#include "thread/Task.h" +#include "thread/TaskManager.h" +#include "thread/TaskProcessor.h" +#include "utils/TraceUtils.h" + +#include <SkPicture.h> +#include <SkRefCnt.h> +#include <SkTime.h> +#include <SkTLazy.h> + +namespace android { + +AnimatedImageDrawable::AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage) + : mSkAnimatedImage(std::move(animatedImage)) { } + +void AnimatedImageDrawable::syncProperties() { + mAlpha = mStagingAlpha; + mColorFilter = mStagingColorFilter; +} + +void AnimatedImageDrawable::start() { + SkAutoExclusive lock(mLock); + + mSnapshot.reset(mSkAnimatedImage->newPictureSnapshot()); + + mSkAnimatedImage->start(); +} + +void AnimatedImageDrawable::stop() { + SkAutoExclusive lock(mLock); + mSkAnimatedImage->stop(); + mSnapshot.reset(nullptr); +} + +bool AnimatedImageDrawable::isRunning() { + return mSkAnimatedImage->isRunning(); +} + +// This is really a Task<void> but that doesn't really work when Future<> +// expects to be able to get/set a value +class AnimatedImageDrawable::AnimatedImageTask : public uirenderer::Task<bool> { +public: + AnimatedImageTask(AnimatedImageDrawable* animatedImageDrawable) + : mAnimatedImageDrawable(sk_ref_sp(animatedImageDrawable)) {} + + sk_sp<AnimatedImageDrawable> mAnimatedImageDrawable; + bool mIsCompleted = false; +}; + +class AnimatedImageDrawable::AnimatedImageTaskProcessor : public uirenderer::TaskProcessor<bool> { +public: + explicit AnimatedImageTaskProcessor(uirenderer::TaskManager* taskManager) + : uirenderer::TaskProcessor<bool>(taskManager) {} + ~AnimatedImageTaskProcessor() {} + + virtual void onProcess(const sp<uirenderer::Task<bool>>& task) override { + ATRACE_NAME("Updating AnimatedImageDrawables"); + AnimatedImageTask* t = static_cast<AnimatedImageTask*>(task.get()); + t->mAnimatedImageDrawable->update(); + t->mIsCompleted = true; + task->setResult(true); + }; +}; + +void AnimatedImageDrawable::scheduleUpdate(uirenderer::TaskManager* taskManager) { + if (!mSkAnimatedImage->isRunning() + || (mDecodeTask.get() != nullptr && !mDecodeTask->mIsCompleted)) { + return; + } + + if (!mDecodeTaskProcessor.get()) { + mDecodeTaskProcessor = new AnimatedImageTaskProcessor(taskManager); + } + + // TODO get one frame ahead and only schedule updates when you need to replenish + mDecodeTask = new AnimatedImageTask(this); + mDecodeTaskProcessor->add(mDecodeTask); +} + +void AnimatedImageDrawable::update() { + SkAutoExclusive lock(mLock); + + if (!mSkAnimatedImage->isRunning()) { + return; + } + + const double currentTime = SkTime::GetMSecs(); + if (currentTime >= mNextFrameTime) { + mNextFrameTime = mSkAnimatedImage->update(currentTime); + mSnapshot.reset(mSkAnimatedImage->newPictureSnapshot()); + mIsDirty = true; + } +} + +void AnimatedImageDrawable::onDraw(SkCanvas* canvas) { + SkTLazy<SkPaint> lazyPaint; + if (mAlpha != SK_AlphaOPAQUE || mColorFilter.get()) { + lazyPaint.init(); + lazyPaint.get()->setAlpha(mAlpha); + lazyPaint.get()->setColorFilter(mColorFilter); + lazyPaint.get()->setFilterQuality(kLow_SkFilterQuality); + } + + SkAutoExclusive lock(mLock); + if (mSkAnimatedImage->isRunning()) { + canvas->drawPicture(mSnapshot, nullptr, lazyPaint.getMaybeNull()); + } else { + // TODO: we could potentially keep the cached surface around if there is a paint and we know + // the drawable is attached to the view system + SkAutoCanvasRestore acr(canvas, false); + if (lazyPaint.isValid()) { + canvas->saveLayer(mSkAnimatedImage->getBounds(), lazyPaint.get()); + } + mSkAnimatedImage->draw(canvas); + } + + mIsDirty = false; +} + +double AnimatedImageDrawable::drawStaging(SkCanvas* canvas) { + // update the drawable with the current time + double nextUpdate = mSkAnimatedImage->update(SkTime::GetMSecs()); + SkAutoCanvasRestore acr(canvas, false); + if (mStagingAlpha != SK_AlphaOPAQUE || mStagingColorFilter.get()) { + SkPaint paint; + paint.setAlpha(mStagingAlpha); + paint.setColorFilter(mStagingColorFilter); + canvas->saveLayer(mSkAnimatedImage->getBounds(), &paint); + } + canvas->drawDrawable(mSkAnimatedImage.get()); + return nextUpdate; +} + +}; // namespace android diff --git a/libs/hwui/hwui/AnimatedImageDrawable.h b/libs/hwui/hwui/AnimatedImageDrawable.h new file mode 100644 index 000000000000..18764afde138 --- /dev/null +++ b/libs/hwui/hwui/AnimatedImageDrawable.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cutils/compiler.h> +#include <utils/RefBase.h> + +#include <SkAnimatedImage.h> +#include <SkCanvas.h> +#include <SkColorFilter.h> +#include <SkDrawable.h> +#include <SkMutex.h> + +class SkPicture; + +namespace android { + +namespace uirenderer { +class TaskManager; +} + +/** + * Native component of android.graphics.drawable.AnimatedImageDrawables.java. This class can be + * drawn into Canvas.h and maintains the state needed to drive the animation from the RenderThread. + */ +class ANDROID_API AnimatedImageDrawable : public SkDrawable { +public: + AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage); + + /** + * This returns true if the animation has updated and signals that the next draw will contain + * new content. + */ + bool isDirty() const { return mIsDirty; } + + int getStagingAlpha() const { return mStagingAlpha; } + void setStagingAlpha(int alpha) { mStagingAlpha = alpha; } + void setStagingColorFilter(sk_sp<SkColorFilter> filter) { mStagingColorFilter = filter; } + void syncProperties(); + + virtual SkRect onGetBounds() override { + return mSkAnimatedImage->getBounds(); + } + + double drawStaging(SkCanvas* canvas); + + void start(); + void stop(); + bool isRunning(); + + void scheduleUpdate(uirenderer::TaskManager* taskManager); + +protected: + virtual void onDraw(SkCanvas* canvas) override; + +private: + void update(); + + sk_sp<SkAnimatedImage> mSkAnimatedImage; + sk_sp<SkPicture> mSnapshot; + SkMutex mLock; + + int mStagingAlpha = SK_AlphaOPAQUE; + sk_sp<SkColorFilter> mStagingColorFilter; + + int mAlpha = SK_AlphaOPAQUE; + sk_sp<SkColorFilter> mColorFilter; + double mNextFrameTime = 0.0; + bool mIsDirty = false; + + class AnimatedImageTask; + class AnimatedImageTaskProcessor; + sp<AnimatedImageTask> mDecodeTask; + sp<AnimatedImageTaskProcessor> mDecodeTaskProcessor; +}; + +}; // namespace android diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h index 5efd35764635..cae4542b18e8 100644 --- a/libs/hwui/hwui/Canvas.h +++ b/libs/hwui/hwui/Canvas.h @@ -73,6 +73,7 @@ typedef uirenderer::VectorDrawable::Tree VectorDrawableRoot; typedef std::function<void(uint16_t* text, float* positions)> ReadGlyphFunc; +class AnimatedImageDrawable; class Bitmap; class Paint; struct Typeface; @@ -238,8 +239,7 @@ public: float dstTop, float dstRight, float dstBottom, const SkPaint* paint) = 0; - virtual void drawAnimatedImage(SkAnimatedImage*, float left, float top, - const SkPaint* paint) = 0; + virtual double drawAnimatedImage(AnimatedImageDrawable* imgDrawable) = 0; /** * Specifies if the positions passed to ::drawText are absolute or relative diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp index cb10901c4ccf..cf0b6a4d1dcc 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp @@ -31,6 +31,9 @@ void SkiaDisplayList::syncContents() { for (auto& functor : mChildFunctors) { functor.syncFunctor(); } + for (auto& animatedImage : mAnimatedImages) { + animatedImage->syncProperties(); + } for (auto& vectorDrawable : mVectorDrawables) { vectorDrawable->syncProperties(); } @@ -89,6 +92,18 @@ bool SkiaDisplayList::prepareListAndChildren( } bool isDirty = false; + for (auto& animatedImage : mAnimatedImages) { + // If any animated image in the display list needs updated, then damage the node. + if (animatedImage->isDirty()) { + isDirty = true; + } + if (animatedImage->isRunning()) { + static_cast<SkiaPipeline*>(info.canvasContext.getRenderPipeline()) + ->scheduleDeferredUpdate(animatedImage); + info.out.hasAnimations = true; + } + } + for (auto& vectorDrawable : mVectorDrawables) { // If any vector drawable in the display list needs update, damage the node. if (vectorDrawable->isDirty()) { @@ -109,6 +124,7 @@ void SkiaDisplayList::reset() { mMutableImages.clear(); mVectorDrawables.clear(); + mAnimatedImages.clear(); mChildFunctors.clear(); mChildNodes.clear(); diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h index 6883d33291ec..818ec114a5b3 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.h +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h @@ -17,6 +17,7 @@ #pragma once #include "DisplayList.h" +#include "hwui/AnimatedImageDrawable.h" #include "GLFunctorDrawable.h" #include "RenderNodeDrawable.h" @@ -144,6 +145,7 @@ public: std::deque<GLFunctorDrawable> mChildFunctors; std::vector<SkImage*> mMutableImages; std::vector<VectorDrawableRoot*> mVectorDrawables; + std::vector<AnimatedImageDrawable*> mAnimatedImages; SkLiteDL mDisplayList; // mProjectionReceiver points to a child node (stored in mChildNodes) that is as a projection diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp index 9db39d954e4c..534782a5dc02 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp @@ -40,6 +40,7 @@ uint8_t SkiaPipeline::mSpotShadowAlpha = 0; Vector3 SkiaPipeline::mLightCenter = {FLT_MIN, FLT_MIN, FLT_MIN}; SkiaPipeline::SkiaPipeline(RenderThread& thread) : mRenderThread(thread) { + mAnimatedImageDrawables.reserve(30); mVectorDrawables.reserve(30); } @@ -326,6 +327,15 @@ void SkiaPipeline::renderFrame(const LayerUpdateQueue& layers, const SkRect& cli ATRACE_NAME("flush commands"); surface->getCanvas()->flush(); + + // TODO move to another method + if (!mAnimatedImageDrawables.empty()) { + ATRACE_NAME("Update AnimatedImageDrawables"); + for (auto animatedImage : mAnimatedImageDrawables) { + animatedImage->scheduleUpdate(getTaskManager()); + } + mAnimatedImageDrawables.clear(); + } } namespace { diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h index 27092270bb80..cc75e9c5b38d 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaPipeline.h @@ -18,6 +18,7 @@ #include <SkSurface.h> #include "FrameBuilder.h" +#include "hwui/AnimatedImageDrawable.h" #include "renderthread/CanvasContext.h" #include "renderthread/IRenderPipeline.h" @@ -54,6 +55,12 @@ public: std::vector<VectorDrawableRoot*>* getVectorDrawables() { return &mVectorDrawables; } + void scheduleDeferredUpdate(AnimatedImageDrawable* imageDrawable) { + mAnimatedImageDrawables.push_back(imageDrawable); + } + + std::vector<AnimatedImageDrawable*>* getAnimatingImages() { return &mAnimatedImageDrawables; } + static void destroyLayer(RenderNode* node); static void prepareToDraw(const renderthread::RenderThread& thread, Bitmap* bitmap); @@ -137,6 +144,11 @@ private: */ std::vector<VectorDrawableRoot*> mVectorDrawables; + /** + * populated by prepareTree with images with active animations + */ + std::vector<AnimatedImageDrawable*> mAnimatedImageDrawables; + // Block of properties used only for debugging to record a SkPicture and save it in a file. /** * mCapturedFile is used to enforce we don't capture more than once for a given name (cause diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp index 035cea3f61b0..eabe2e87fc49 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp @@ -246,6 +246,12 @@ void SkiaRecordingCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& ch } } +double SkiaRecordingCanvas::drawAnimatedImage(AnimatedImageDrawable* animatedImage) { + drawDrawable(animatedImage); + mDisplayList->mAnimatedImages.push_back(animatedImage); + return 0; +} + }; // namespace skiapipeline }; // namespace uirenderer }; // namespace android diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h index d35bbabb652f..0e5dbdbab078 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h @@ -53,6 +53,7 @@ public: virtual void drawNinePatch(Bitmap& hwuiBitmap, const android::Res_png_9patch& chunk, float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) override; + virtual double drawAnimatedImage(AnimatedImageDrawable* animatedImage) override; virtual void drawRoundRect(uirenderer::CanvasPropertyPrimitive* left, uirenderer::CanvasPropertyPrimitive* top, |