diff options
Diffstat (limited to 'libs/hwui')
-rw-r--r-- | libs/hwui/Android.mk | 1 | ||||
-rw-r--r-- | libs/hwui/AnimationContext.cpp | 126 | ||||
-rw-r--r-- | libs/hwui/AnimationContext.h | 112 | ||||
-rw-r--r-- | libs/hwui/Animator.cpp | 32 | ||||
-rw-r--r-- | libs/hwui/Animator.h | 12 | ||||
-rw-r--r-- | libs/hwui/AnimatorManager.cpp | 86 | ||||
-rw-r--r-- | libs/hwui/AnimatorManager.h | 17 | ||||
-rw-r--r-- | libs/hwui/IContextFactory.h | 39 | ||||
-rw-r--r-- | libs/hwui/RenderNode.cpp | 2 | ||||
-rw-r--r-- | libs/hwui/RenderNode.h | 2 | ||||
-rw-r--r-- | libs/hwui/TreeInfo.h | 15 | ||||
-rw-r--r-- | libs/hwui/renderthread/CanvasContext.cpp | 10 | ||||
-rw-r--r-- | libs/hwui/renderthread/CanvasContext.h | 7 | ||||
-rw-r--r-- | libs/hwui/renderthread/RenderProxy.cpp | 9 | ||||
-rw-r--r-- | libs/hwui/renderthread/RenderProxy.h | 3 | ||||
-rw-r--r-- | libs/hwui/renderthread/TimeLord.cpp | 2 | ||||
-rw-r--r-- | libs/hwui/renderthread/TimeLord.h | 2 |
17 files changed, 417 insertions, 60 deletions
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index d9f7941..49560ff 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -12,6 +12,7 @@ ifeq ($(USE_OPENGL_RENDERER),true) font/CacheTexture.cpp \ font/Font.cpp \ AmbientShadow.cpp \ + AnimationContext.cpp \ Animator.cpp \ AnimatorManager.cpp \ AssetAtlas.cpp \ diff --git a/libs/hwui/AnimationContext.cpp b/libs/hwui/AnimationContext.cpp new file mode 100644 index 0000000..ec44de3 --- /dev/null +++ b/libs/hwui/AnimationContext.cpp @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2014 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 "AnimationContext.h" + +#include "Animator.h" +#include "RenderNode.h" +#include "TreeInfo.h" +#include "renderthread/TimeLord.h" + +namespace android { +namespace uirenderer { + +AnimationContext::AnimationContext(renderthread::TimeLord& clock) + : mClock(clock) + , mCurrentFrameAnimations(*this) + , mNextFrameAnimations(*this) + , mFrameTimeMs(0) { +} + +AnimationContext::~AnimationContext() { +} + +void AnimationContext::addAnimatingRenderNode(RenderNode& node) { + if (!node.animators().hasAnimationHandle()) { + AnimationHandle* handle = new AnimationHandle(node, *this); + addAnimationHandle(handle); + } +} + +void AnimationContext::addAnimationHandle(AnimationHandle* handle) { + handle->insertAfter(&mNextFrameAnimations); +} + +void AnimationContext::startFrame() { + LOG_ALWAYS_FATAL_IF(mCurrentFrameAnimations.mNextHandle, + "Missed running animations last frame!"); + AnimationHandle* head = mNextFrameAnimations.mNextHandle; + if (head) { + mNextFrameAnimations.mNextHandle = NULL; + mCurrentFrameAnimations.mNextHandle = head; + head->mPreviousHandle = &mCurrentFrameAnimations; + } + mFrameTimeMs = mClock.computeFrameTimeMs(); +} + +void AnimationContext::runRemainingAnimations(TreeInfo& info) { + while (mCurrentFrameAnimations.mNextHandle) { + AnimationHandle* current = mCurrentFrameAnimations.mNextHandle; + AnimatorManager& animators = current->mRenderNode->animators(); + animators.pushStaging(); + animators.animateNoDamage(info); + LOG_ALWAYS_FATAL_IF(mCurrentFrameAnimations.mNextHandle == current, + "Animate failed to remove from current frame list!"); + } +} + +void AnimationContext::callOnFinished(BaseRenderNodeAnimator* animator, + AnimationListener* listener) { + listener->onAnimationFinished(animator); +} + +AnimationHandle::AnimationHandle(AnimationContext& context) + : mContext(context) + , mPreviousHandle(NULL) + , mNextHandle(NULL) { +} + +AnimationHandle::AnimationHandle(RenderNode& animatingNode, AnimationContext& context) + : mRenderNode(&animatingNode) + , mContext(context) + , mPreviousHandle(NULL) + , mNextHandle(NULL) { + mRenderNode->animators().setAnimationHandle(this); +} + +AnimationHandle::~AnimationHandle() { + LOG_ALWAYS_FATAL_IF(mPreviousHandle || mNextHandle, + "AnimationHandle destroyed while still animating!"); +} + +void AnimationHandle::notifyAnimationsRan() { + removeFromList(); + if (mRenderNode->animators().hasAnimators()) { + mContext.addAnimationHandle(this); + } else { + mRenderNode->animators().setAnimationHandle(NULL); + delete this; + } +} + +void AnimationHandle::insertAfter(AnimationHandle* prev) { + removeFromList(); + mNextHandle = prev->mNextHandle; + if (mNextHandle) { + mNextHandle->mPreviousHandle = this; + } + prev->mNextHandle = this; + mPreviousHandle = prev; +} + +void AnimationHandle::removeFromList() { + if (mPreviousHandle) { + mPreviousHandle->mNextHandle = mNextHandle; + } + if (mNextHandle) { + mNextHandle->mPreviousHandle = mPreviousHandle; + } + mPreviousHandle = NULL; + mNextHandle = NULL; +} + +} /* namespace uirenderer */ +} /* namespace android */ diff --git a/libs/hwui/AnimationContext.h b/libs/hwui/AnimationContext.h new file mode 100644 index 0000000..e32c33d --- /dev/null +++ b/libs/hwui/AnimationContext.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2014 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. + */ +#ifndef TREEANIMATIONTRACKER_H_ +#define TREEANIMATIONTRACKER_H_ + +#include <cutils/compiler.h> +#include <utils/RefBase.h> +#include <utils/StrongPointer.h> + +#include "renderthread/TimeLord.h" +#include "utils/Macros.h" + +namespace android { +namespace uirenderer { + +class AnimationContext; +class AnimationListener; +class BaseRenderNodeAnimator; +class RenderNode; +class TreeInfo; + +/* + * AnimationHandle is several classes merged into one. + * 1: It maintains the reference to the AnimationContext required to run animators. + * 2: It keeps a strong reference to RenderNodes with animators so that + * we don't lose them if they are no longer in the display tree. This is + * required so that we can keep animating them, and properly notify listeners + * of onAnimationFinished. + * 3: It forms a doubly linked list so that we can cheaply move between states. + */ +class AnimationHandle { + PREVENT_COPY_AND_ASSIGN(AnimationHandle); +public: + AnimationContext& context() { return mContext; } + + void notifyAnimationsRan(); + +private: + friend class AnimationContext; + AnimationHandle(AnimationContext& context); + AnimationHandle(RenderNode& animatingNode, AnimationContext& context); + ~AnimationHandle(); + + void insertAfter(AnimationHandle* prev); + void removeFromList(); + + sp<RenderNode> mRenderNode; + + AnimationContext& mContext; + + AnimationHandle* mPreviousHandle; + AnimationHandle* mNextHandle; +}; + +class AnimationContext { + PREVENT_COPY_AND_ASSIGN(AnimationContext); +public: + ANDROID_API AnimationContext(renderthread::TimeLord& clock); + ANDROID_API virtual ~AnimationContext(); + + nsecs_t frameTimeMs() { return mFrameTimeMs; } + bool hasAnimations() { + return mCurrentFrameAnimations.mNextHandle + || mNextFrameAnimations.mNextHandle; + } + + // Will always add to the next frame list, which is swapped when + // startFrame() is called + ANDROID_API void addAnimatingRenderNode(RenderNode& node); + + // Marks the start of a frame, which will update the frame time and move all + // next frame animations into the current frame + ANDROID_API virtual void startFrame(); + + // Runs any animations still left in mCurrentFrameAnimations that were not run + // as part of the standard RenderNode:prepareTree pass. + ANDROID_API virtual void runRemainingAnimations(TreeInfo& info); + + ANDROID_API virtual void callOnFinished(BaseRenderNodeAnimator* animator, AnimationListener* listener); + +private: + friend class AnimationHandle; + void addAnimationHandle(AnimationHandle* handle); + + renderthread::TimeLord& mClock; + + // Animations left to run this frame, at the end of the frame this should + // be null + AnimationHandle mCurrentFrameAnimations; + // Animations queued for next frame + AnimationHandle mNextFrameAnimations; + + nsecs_t mFrameTimeMs; +}; + +} /* namespace uirenderer */ +} /* namespace android */ + +#endif /* TREEANIMATIONTRACKER_H_ */ diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp index 78d569d..1c697d5 100644 --- a/libs/hwui/Animator.cpp +++ b/libs/hwui/Animator.cpp @@ -19,6 +19,7 @@ #include <inttypes.h> #include <set> +#include "AnimationContext.h" #include "RenderNode.h" #include "RenderProperties.h" @@ -85,7 +86,7 @@ void BaseRenderNodeAnimator::attach(RenderNode* target) { onAttached(); } -void BaseRenderNodeAnimator::pushStaging(TreeInfo& info) { +void BaseRenderNodeAnimator::pushStaging(AnimationContext& context) { if (!mHasStartValue) { doSetStartValue(getValue(mTarget)); } @@ -93,21 +94,22 @@ void BaseRenderNodeAnimator::pushStaging(TreeInfo& info) { mPlayState = mStagingPlayState; // Oh boy, we're starting! Man the battle stations! if (mPlayState == RUNNING) { - transitionToRunning(info); + transitionToRunning(context); } } } -void BaseRenderNodeAnimator::transitionToRunning(TreeInfo& info) { - LOG_ALWAYS_FATAL_IF(info.frameTimeMs <= 0, "%" PRId64 " isn't a real frame time!", info.frameTimeMs); +void BaseRenderNodeAnimator::transitionToRunning(AnimationContext& context) { + nsecs_t frameTimeMs = context.frameTimeMs(); + LOG_ALWAYS_FATAL_IF(frameTimeMs <= 0, "%" PRId64 " isn't a real frame time!", frameTimeMs); if (mStartDelay < 0 || mStartDelay > 50000) { ALOGW("Your start delay is strange and confusing: %" PRId64, mStartDelay); } - mStartTime = info.frameTimeMs + mStartDelay; + mStartTime = frameTimeMs + mStartDelay; if (mStartTime < 0) { ALOGW("Ended up with a really weird start time of %" PRId64 " with frame time %" PRId64 " and start delay %" PRId64, - mStartTime, info.frameTimeMs, mStartDelay); + mStartTime, frameTimeMs, mStartDelay); // Set to 0 so that the animate() basically instantly finishes mStartTime = 0; } @@ -120,7 +122,7 @@ void BaseRenderNodeAnimator::transitionToRunning(TreeInfo& info) { } } -bool BaseRenderNodeAnimator::animate(TreeInfo& info) { +bool BaseRenderNodeAnimator::animate(AnimationContext& context) { if (mPlayState < RUNNING) { return false; } @@ -132,15 +134,14 @@ bool BaseRenderNodeAnimator::animate(TreeInfo& info) { // because the staging properties reflect the final value, we always need // to call setValue even if the animation isn't yet running or is still // being delayed as we need to override the staging value - if (mStartTime > info.frameTimeMs) { - info.out.hasAnimations |= true; + if (mStartTime > context.frameTimeMs()) { setValue(mTarget, mFromValue); return false; } float fraction = 1.0f; if (mPlayState == RUNNING && mDuration > 0) { - fraction = (float)(info.frameTimeMs - mStartTime) / mDuration; + fraction = (float)(context.frameTimeMs() - mStartTime) / mDuration; } if (fraction >= 1.0f) { fraction = 1.0f; @@ -151,21 +152,16 @@ bool BaseRenderNodeAnimator::animate(TreeInfo& info) { setValue(mTarget, mFromValue + (mDeltaValue * fraction)); if (mPlayState == FINISHED) { - callOnFinishedListener(info); + callOnFinishedListener(context); return true; } - info.out.hasAnimations |= true; return false; } -void BaseRenderNodeAnimator::callOnFinishedListener(TreeInfo& info) { +void BaseRenderNodeAnimator::callOnFinishedListener(AnimationContext& context) { if (mListener.get()) { - if (!info.animationHook) { - mListener->onAnimationFinished(this); - } else { - info.animationHook->callOnFinished(this, mListener.get()); - } + context.callOnFinished(this, mListener.get()); } } diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h index 6dfe7b4..c52a93f 100644 --- a/libs/hwui/Animator.h +++ b/libs/hwui/Animator.h @@ -28,6 +28,8 @@ namespace android { namespace uirenderer { +class AnimationContext; +class BaseRenderNodeAnimator; class RenderNode; class RenderProperties; @@ -50,15 +52,17 @@ public: ANDROID_API void setListener(AnimationListener* listener) { mListener = listener; } + AnimationListener* listener() { return mListener.get(); } ANDROID_API void start() { mStagingPlayState = RUNNING; onStagingPlayStateChanged(); } ANDROID_API void end() { mStagingPlayState = FINISHED; onStagingPlayStateChanged(); } void attach(RenderNode* target); virtual void onAttached() {} void detach() { mTarget = 0; } - void pushStaging(TreeInfo& info); - bool animate(TreeInfo& info); + void pushStaging(AnimationContext& context); + bool animate(AnimationContext& context); + bool isRunning() { return mPlayState == RUNNING; } bool isFinished() { return mPlayState == FINISHED; } float finalValue() { return mFinalValue; } @@ -72,7 +76,7 @@ protected: virtual void setValue(RenderNode* target, float value) = 0; RenderNode* target() { return mTarget; } - void callOnFinishedListener(TreeInfo& info); + void callOnFinishedListener(AnimationContext& context); virtual void onStagingPlayStateChanged() {} @@ -100,7 +104,7 @@ protected: private: inline void checkMutable(); - virtual void transitionToRunning(TreeInfo& info); + virtual void transitionToRunning(AnimationContext& context); void doSetStartValue(float value); }; diff --git a/libs/hwui/AnimatorManager.cpp b/libs/hwui/AnimatorManager.cpp index 7221295a4..3832d42 100644 --- a/libs/hwui/AnimatorManager.cpp +++ b/libs/hwui/AnimatorManager.cpp @@ -17,6 +17,7 @@ #include <algorithm> +#include "AnimationContext.h" #include "RenderNode.h" namespace android { @@ -30,7 +31,8 @@ static void unref(BaseRenderNodeAnimator* animator) { } AnimatorManager::AnimatorManager(RenderNode& parent) - : mParent(parent) { + : mParent(parent) + , mAnimationHandle(NULL) { } AnimatorManager::~AnimatorManager() { @@ -44,6 +46,11 @@ void AnimatorManager::addAnimator(const sp<BaseRenderNodeAnimator>& animator) { mNewAnimators.push_back(animator.get()); } +void AnimatorManager::setAnimationHandle(AnimationHandle* handle) { + LOG_ALWAYS_FATAL_IF(mAnimationHandle && handle, "Already have an AnimationHandle!"); + mAnimationHandle = handle; +} + template<typename T> static void move_all(T& source, T& dest) { dest.reserve(source.size() + dest.size()); @@ -53,26 +60,30 @@ static void move_all(T& source, T& dest) { source.clear(); } -void AnimatorManager::pushStaging(TreeInfo& info) { +void AnimatorManager::pushStaging() { if (mNewAnimators.size()) { // Since this is a straight move, we don't need to inc/dec the ref count move_all(mNewAnimators, mAnimators); } for (vector<BaseRenderNodeAnimator*>::iterator it = mAnimators.begin(); it != mAnimators.end(); it++) { - (*it)->pushStaging(info); + (*it)->pushStaging(mAnimationHandle->context()); } } class AnimateFunctor { public: - AnimateFunctor(RenderNode& target, TreeInfo& info) - : dirtyMask(0), mTarget(target), mInfo(info) {} + AnimateFunctor(TreeInfo& info, AnimationContext& context) + : dirtyMask(0), mInfo(info), mContext(context) {} bool operator() (BaseRenderNodeAnimator* animator) { dirtyMask |= animator->dirtyMask(); - bool remove = animator->animate(mInfo); + bool remove = animator->animate(mContext); if (remove) { animator->decStrong(0); + } else { + if (animator->isRunning()) { + mInfo.out.hasAnimations = true; + } } return remove; } @@ -80,8 +91,8 @@ public: uint32_t dirtyMask; private: - RenderNode& mTarget; TreeInfo& mInfo; + AnimationContext& mContext; }; uint32_t AnimatorManager::animate(TreeInfo& info) { @@ -93,17 +104,70 @@ uint32_t AnimatorManager::animate(TreeInfo& info) { mParent.damageSelf(info); info.damageAccumulator->popTransform(); - AnimateFunctor functor(mParent, info); - std::vector< BaseRenderNodeAnimator* >::iterator newEnd; - newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor); - mAnimators.erase(newEnd, mAnimators.end()); + uint32_t dirty = animateCommon(info); mParent.mProperties.updateMatrix(); info.damageAccumulator->pushTransform(&mParent); mParent.damageSelf(info); + return dirty; +} + +void AnimatorManager::animateNoDamage(TreeInfo& info) { + if (!mAnimators.size()) return; + + animateCommon(info); +} + +uint32_t AnimatorManager::animateCommon(TreeInfo& info) { + AnimateFunctor functor(info, mAnimationHandle->context()); + std::vector< BaseRenderNodeAnimator* >::iterator newEnd; + newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor); + mAnimators.erase(newEnd, mAnimators.end()); + mAnimationHandle->notifyAnimationsRan(); return functor.dirtyMask; } +class EndAnimatorsFunctor { +public: + EndAnimatorsFunctor(AnimationContext& context) : mContext(context) {} + + void operator() (BaseRenderNodeAnimator* animator) { + animator->end(); + animator->pushStaging(mContext); + animator->animate(mContext); + animator->decStrong(0); + } + +private: + AnimationContext& mContext; +}; + +static void endAnimatorsHard(BaseRenderNodeAnimator* animator) { + animator->end(); + if (animator->listener()) { + animator->listener()->onAnimationFinished(animator); + } + animator->decStrong(0); +} + +void AnimatorManager::endAllAnimators() { + if (mNewAnimators.size()) { + // Since this is a straight move, we don't need to inc/dec the ref count + move_all(mNewAnimators, mAnimators); + } + // First try gracefully ending them + if (mAnimationHandle) { + EndAnimatorsFunctor functor(mAnimationHandle->context()); + for_each(mAnimators.begin(), mAnimators.end(), functor); + } else { + // We have no context, so bust out the sledgehammer + // This works because this state can only happen on the UI thread, + // which means we're already on the right thread to invoke listeners + for_each(mAnimators.begin(), mAnimators.end(), endAnimatorsHard); + } + mAnimators.clear(); +} + } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/AnimatorManager.h b/libs/hwui/AnimatorManager.h index 0d177c5..d5f56ed 100644 --- a/libs/hwui/AnimatorManager.h +++ b/libs/hwui/AnimatorManager.h @@ -27,6 +27,7 @@ namespace android { namespace uirenderer { +class AnimationHandle; class BaseRenderNodeAnimator; class RenderNode; @@ -39,12 +40,26 @@ public: void addAnimator(const sp<BaseRenderNodeAnimator>& animator); - void pushStaging(TreeInfo& info); + void setAnimationHandle(AnimationHandle* handle); + bool hasAnimationHandle() { return mAnimationHandle; } + + void pushStaging(); + // Returns the combined dirty mask of all animators run uint32_t animate(TreeInfo& info); + void animateNoDamage(TreeInfo& info); + + // Hard-ends all animators. Used for cleanup if the root is being destroyed. + ANDROID_API void endAllAnimators(); + + bool hasAnimators() { return mAnimators.size(); } + private: + uint32_t animateCommon(TreeInfo& info); + RenderNode& mParent; + AnimationHandle* mAnimationHandle; // To improve the efficiency of resizing & removing from the vector // use manual ref counting instead of sp<>. diff --git a/libs/hwui/IContextFactory.h b/libs/hwui/IContextFactory.h new file mode 100644 index 0000000..463b55e --- /dev/null +++ b/libs/hwui/IContextFactory.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2014 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. + */ +#ifndef CONTEXTFACTORY_H_ +#define CONTEXTFACTORY_H_ + +namespace android { +namespace uirenderer { + +namespace renderthread { +class TimeLord; +} + +class AnimationContext; + +class IContextFactory { +public: + virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) = 0; + +protected: + virtual ~IContextFactory() {} +}; + +} /* namespace uirenderer */ +} /* namespace android */ + +#endif /* CONTEXTFACTORY_H_ */ diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index 658265d..a79875e 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -235,7 +235,7 @@ void RenderNode::pushStagingPropertiesChanges(TreeInfo& info) { // before properties() is trampled by stagingProperties(), as they are // required by some animators. if (CC_LIKELY(info.runAnimations)) { - mAnimatorManager.pushStaging(info); + mAnimatorManager.pushStaging(); } if (mDirtyPropertyFields) { mDirtyPropertyFields = 0; diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index 18402b2..27b05e2 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -174,6 +174,8 @@ public: // UI thread only! ANDROID_API void addAnimator(const sp<BaseRenderNodeAnimator>& animator); + AnimatorManager& animators() { return mAnimatorManager; } + void applyViewPropertyTransforms(mat4& matrix, bool true3dTransform = false) const; private: diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h index 74d52a3..e78d8bd 100644 --- a/libs/hwui/TreeInfo.h +++ b/libs/hwui/TreeInfo.h @@ -26,18 +26,9 @@ namespace android { namespace uirenderer { -class BaseRenderNodeAnimator; -class AnimationListener; class OpenGLRenderer; class RenderState; -class AnimationHook { -public: - virtual void callOnFinished(BaseRenderNodeAnimator* animator, AnimationListener* listener) = 0; -protected: - ~AnimationHook() {} -}; - class ErrorHandler { public: virtual void onError(const std::string& message) = 0; @@ -62,8 +53,6 @@ public: explicit TreeInfo(TraversalMode mode, RenderState& renderState) : mode(mode) - , frameTimeMs(0) - , animationHook(NULL) , prepareTextures(mode == MODE_FULL) , runAnimations(true) , damageAccumulator(NULL) @@ -74,8 +63,6 @@ public: explicit TreeInfo(TraversalMode mode, const TreeInfo& clone) : mode(mode) - , frameTimeMs(clone.frameTimeMs) - , animationHook(clone.animationHook) , prepareTextures(mode == MODE_FULL) , runAnimations(clone.runAnimations) , damageAccumulator(clone.damageAccumulator) @@ -85,8 +72,6 @@ public: {} const TraversalMode mode; - nsecs_t frameTimeMs; - AnimationHook* animationHook; // TODO: Remove this? Currently this is used to signal to stop preparing // textures if we run out of cache space. bool prepareTextures; diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 4bf5a8a..d9fa0bc 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -21,6 +21,7 @@ #include "EglManager.h" #include "RenderThread.h" +#include "../AnimationContext.h" #include "../Caches.h" #include "../DeferredLayerUpdater.h" #include "../RenderState.h" @@ -35,7 +36,8 @@ namespace android { namespace uirenderer { namespace renderthread { -CanvasContext::CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode) +CanvasContext::CanvasContext(RenderThread& thread, bool translucent, + RenderNode* rootRenderNode, IContextFactory* contextFactory) : mRenderThread(thread) , mEglManager(thread.eglManager()) , mEglSurface(EGL_NO_SURFACE) @@ -44,11 +46,13 @@ CanvasContext::CanvasContext(RenderThread& thread, bool translucent, RenderNode* , mCanvas(NULL) , mHaveNewSurface(false) , mRootRenderNode(rootRenderNode) { + mAnimationContext = contextFactory->createAnimationContext(mRenderThread.timeLord()); } CanvasContext::~CanvasContext() { destroyCanvasAndSurface(); mRenderThread.removeFrameCallback(this); + delete mAnimationContext; } void CanvasContext::destroyCanvasAndSurface() { @@ -136,10 +140,11 @@ void CanvasContext::processLayerUpdate(DeferredLayerUpdater* layerUpdater) { void CanvasContext::prepareTree(TreeInfo& info) { mRenderThread.removeFrameCallback(this); - info.frameTimeMs = mRenderThread.timeLord().frameTimeMs(); info.damageAccumulator = &mDamageAccumulator; info.renderer = mCanvas; + mAnimationContext->startFrame(); mRootRenderNode->prepareTree(info); + mAnimationContext->runRemainingAnimations(info); int runningBehind = 0; // TODO: This query is moderately expensive, investigate adding some sort @@ -254,7 +259,6 @@ void CanvasContext::buildLayer(RenderNode* node) { stopDrawing(); TreeInfo info(TreeInfo::MODE_FULL, mRenderThread.renderState()); - info.frameTimeMs = mRenderThread.timeLord().frameTimeMs(); info.damageAccumulator = &mDamageAccumulator; info.renderer = mCanvas; info.runAnimations = false; diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 0cbed6f..749da1b 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -25,6 +25,7 @@ #include "../DamageAccumulator.h" #include "../DrawProfiler.h" +#include "../IContextFactory.h" #include "../RenderNode.h" #include "RenderTask.h" #include "RenderThread.h" @@ -34,6 +35,7 @@ namespace android { namespace uirenderer { +class AnimationContext; class DeferredLayerUpdater; class OpenGLRenderer; class Rect; @@ -45,9 +47,11 @@ class EglManager; // This per-renderer class manages the bridge between the global EGL context // and the render surface. +// TODO: Rename to Renderer or some other per-window, top-level manager class CanvasContext : public IFrameCallback { public: - CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode); + CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode, + IContextFactory* contextFactory); virtual ~CanvasContext(); bool initialize(ANativeWindow* window); @@ -105,6 +109,7 @@ private: OpenGLRenderer* mCanvas; bool mHaveNewSurface; DamageAccumulator mDamageAccumulator; + AnimationContext* mAnimationContext; const sp<RenderNode> mRootRenderNode; diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 405ce24..3d04316 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -52,17 +52,20 @@ namespace renderthread { MethodInvokeRenderTask* task = new MethodInvokeRenderTask((RunnableMethod) Bridge_ ## method); \ ARGS(method) *args = (ARGS(method) *) task->payload() -CREATE_BRIDGE3(createContext, RenderThread* thread, bool translucent, RenderNode* rootRenderNode) { - return new CanvasContext(*args->thread, args->translucent, args->rootRenderNode); +CREATE_BRIDGE4(createContext, RenderThread* thread, bool translucent, + RenderNode* rootRenderNode, IContextFactory* contextFactory) { + return new CanvasContext(*args->thread, args->translucent, + args->rootRenderNode, args->contextFactory); } -RenderProxy::RenderProxy(bool translucent, RenderNode* rootRenderNode) +RenderProxy::RenderProxy(bool translucent, RenderNode* rootRenderNode, IContextFactory* contextFactory) : mRenderThread(RenderThread::getInstance()) , mContext(0) { SETUP_TASK(createContext); args->translucent = translucent; args->rootRenderNode = rootRenderNode; args->thread = &mRenderThread; + args->contextFactory = contextFactory; mContext = (CanvasContext*) postAndWait(task); mDrawFrameTask.setContext(&mRenderThread, mContext); } diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index eea3674..9e6bcf5 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -30,6 +30,7 @@ #include <utils/Vector.h> #include "../Caches.h" +#include "../IContextFactory.h" #include "DrawFrameTask.h" namespace android { @@ -58,7 +59,7 @@ class RenderProxyBridge; */ class ANDROID_API RenderProxy { public: - ANDROID_API RenderProxy(bool translucent, RenderNode* rootNode); + ANDROID_API RenderProxy(bool translucent, RenderNode* rootNode, IContextFactory* contextFactory); ANDROID_API virtual ~RenderProxy(); ANDROID_API void setFrameInterval(nsecs_t frameIntervalNanos); diff --git a/libs/hwui/renderthread/TimeLord.cpp b/libs/hwui/renderthread/TimeLord.cpp index 758d96e..cf3d039 100644 --- a/libs/hwui/renderthread/TimeLord.cpp +++ b/libs/hwui/renderthread/TimeLord.cpp @@ -30,7 +30,7 @@ void TimeLord::vsyncReceived(nsecs_t vsync) { } } -nsecs_t TimeLord::frameTimeMs() { +nsecs_t TimeLord::computeFrameTimeMs() { // Logic copied from Choreographer.java nsecs_t now = systemTime(CLOCK_MONOTONIC); nsecs_t jitterNanos = now - mFrameTimeNanos; diff --git a/libs/hwui/renderthread/TimeLord.h b/libs/hwui/renderthread/TimeLord.h index 52c6d9e..8b0372c 100644 --- a/libs/hwui/renderthread/TimeLord.h +++ b/libs/hwui/renderthread/TimeLord.h @@ -30,7 +30,7 @@ class TimeLord { public: void setFrameInterval(nsecs_t intervalNanos) { mFrameIntervalNanos = intervalNanos; } void vsyncReceived(nsecs_t vsync); - nsecs_t frameTimeMs(); + nsecs_t computeFrameTimeMs(); private: friend class RenderThread; |