diff options
| -rw-r--r-- | core/java/android/view/SurfaceView.java | 61 | ||||
| -rw-r--r-- | core/jni/android_view_RenderNode.cpp | 32 | ||||
| -rw-r--r-- | libs/hwui/RenderNode.cpp | 23 | ||||
| -rw-r--r-- | libs/hwui/RenderNode.h | 17 |
4 files changed, 102 insertions, 31 deletions
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index d59c8acb9107..17834fb601c4 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -464,7 +464,8 @@ public class SurfaceView extends View { || mUpdateWindowNeeded || mReportDrawNeeded || redrawNeeded) { getLocationInWindow(mLocation); - if (DEBUG) Log.i(TAG, "Changes: creating=" + creating + if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + + "Changes: creating=" + creating + " format=" + formatChanged + " size=" + sizeChanged + " visible=" + visibleChanged + " left=" + (mWindowSpaceLeft != mLocation[0]) @@ -534,7 +535,8 @@ public class SurfaceView extends View { mReportDrawNeeded = false; mDrawingStopped = !visible; - if (DEBUG) Log.i(TAG, "Cur surface: " + mSurface); + if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + + "Cur surface: " + mSurface); relayoutResult = mSession.relayout( mWindow, mWindow.mSeq, mLayout, mWindowSpaceWidth, mWindowSpaceHeight, @@ -547,7 +549,8 @@ public class SurfaceView extends View { reportDrawNeeded = true; } - if (DEBUG) Log.i(TAG, "New surface: " + mNewSurface + if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + + "New surface: " + mNewSurface + ", vis=" + visible + ", frame=" + mWinFrame); mSurfaceFrame.left = 0; @@ -581,7 +584,8 @@ public class SurfaceView extends View { if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) { mSurfaceCreated = false; if (mSurface.isValid()) { - if (DEBUG) Log.i(TAG, "visibleChanged -- surfaceDestroyed"); + if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + + "visibleChanged -- surfaceDestroyed"); callbacks = getSurfaceCallbacks(); for (SurfaceHolder.Callback c : callbacks) { c.surfaceDestroyed(mSurfaceHolder); @@ -594,7 +598,8 @@ public class SurfaceView extends View { if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) { mSurfaceCreated = true; mIsCreating = true; - if (DEBUG) Log.i(TAG, "visibleChanged -- surfaceCreated"); + if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + + "visibleChanged -- surfaceCreated"); if (callbacks == null) { callbacks = getSurfaceCallbacks(); } @@ -604,7 +609,8 @@ public class SurfaceView extends View { } if (creating || formatChanged || sizeChanged || visibleChanged || realSizeChanged) { - if (DEBUG) Log.i(TAG, "surfaceChanged -- format=" + mFormat + if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + + "surfaceChanged -- format=" + mFormat + " w=" + myWidth + " h=" + myHeight); if (callbacks == null) { callbacks = getSurfaceCallbacks(); @@ -614,7 +620,8 @@ public class SurfaceView extends View { } } if (redrawNeeded) { - if (DEBUG) Log.i(TAG, "surfaceRedrawNeeded"); + if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + + "surfaceRedrawNeeded"); if (callbacks == null) { callbacks = getSurfaceCallbacks(); } @@ -629,7 +636,8 @@ public class SurfaceView extends View { } finally { mIsCreating = false; if (redrawNeeded) { - if (DEBUG) Log.i(TAG, "finishedDrawing"); + if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + + "finishedDrawing"); mSession.finishDrawing(mWindow); } mSession.performDeferredDestroy(mWindow); @@ -663,8 +671,9 @@ public class SurfaceView extends View { } try { - Log.d(TAG, String.format("updateWindowPosition UI, " + - "postion = [%d, %d, %d, %d]", mWinFrame.left, mWinFrame.top, + Log.d(TAG, String.format("%d updateWindowPosition UI, " + + "postion = [%d, %d, %d, %d]", System.identityHashCode(this), + mWinFrame.left, mWinFrame.top, mWinFrame.right, mWinFrame.bottom)); mSession.repositionChild(mWindow, mWinFrame.left, mWinFrame.top, mWinFrame.right, mWinFrame.bottom, -1, mWinFrame); @@ -697,9 +706,9 @@ public class SurfaceView extends View { } try { if (DEBUG) { - Log.d(TAG, String.format("updateWindowPosition RT, frameNr = %d, " + - "postion = [%d, %d, %d, %d]", frameNumber, left, top, - right, bottom)); + Log.d(TAG, String.format("%d updateWindowPosition RT, frameNr = %d, " + + "postion = [%d, %d, %d, %d]", System.identityHashCode(this), + frameNumber, left, top, right, bottom)); } // Just using mRTLastReportedPosition as a dummy rect here session.repositionChild(window, left, top, right, bottom, @@ -712,6 +721,25 @@ public class SurfaceView extends View { } } + /** + * Called by native on RenderThread to notify that the window is no longer in the + * draw tree + * @hide + */ + public final void windowPositionLostRT(long frameNumber) { + if (DEBUG) { + Log.d(TAG, String.format("%d windowPositionLostRT RT, frameNr = %d", + System.identityHashCode(this), frameNumber)); + } + // TODO: This is a bit of a hack as we don't have an API to report to WM + // to hide a window with a frameNumber, so just shift the window very far into + // negative space which will do effectively the same thing. + // Use the last reported size to avoid influencing the size of the bufferqueue + int x = -1000 - mRTLastReportedPosition.width(); + int y = -1000 - mRTLastReportedPosition.height(); + updateWindowPositionRT(frameNumber, x, y, -1000, -1000); + } + private SurfaceHolder.Callback[] getSurfaceCallbacks() { SurfaceHolder.Callback callbacks[]; synchronized (mCallbacks) { @@ -750,8 +778,7 @@ public class SurfaceView extends View { boolean alwaysConsumeNavBar) { SurfaceView surfaceView = mSurfaceView.get(); if (surfaceView != null) { - if (DEBUG) Log.v( - "SurfaceView", surfaceView + " got resized: w=" + frame.width() + if (DEBUG) Log.v(TAG, surfaceView + " got resized: w=" + frame.width() + " h=" + frame.height() + ", cur w=" + mCurWidth + " h=" + mCurHeight); surfaceView.mSurfaceLock.lock(); try { @@ -907,7 +934,7 @@ public class SurfaceView extends View { private final Canvas internalLockCanvas(Rect dirty) { mSurfaceLock.lock(); - if (DEBUG) Log.i(TAG, "Locking canvas... stopped=" + if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Locking canvas... stopped=" + mDrawingStopped + ", win=" + mWindow); Canvas c = null; @@ -919,7 +946,7 @@ public class SurfaceView extends View { } } - if (DEBUG) Log.i(TAG, "Returned canvas: " + c); + if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Returned canvas: " + c); if (c != null) { mLastLockTime = SystemClock.uptimeMillis(); return c; diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp index a6db0f43d6c0..4fc546c98e97 100644 --- a/core/jni/android_view_RenderNode.cpp +++ b/core/jni/android_view_RenderNode.cpp @@ -534,6 +534,7 @@ static void android_view_RenderNode_endAllAnimators(JNIEnv* env, jobject clazz, // ---------------------------------------------------------------------------- jmethodID gSurfaceViewPositionUpdateMethod; +jmethodID gSurfaceViewPositionLostMethod; static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject, jlong renderNodePtr, jobject surfaceview) { @@ -581,6 +582,20 @@ static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject, info.canvasContext.enqueueFrameWork(std::move(functor)); } + virtual void onPositionLost(RenderNode& node, const TreeInfo* info) override { + if (CC_UNLIKELY(!mWeakRef || (info && !info->updateWindowPositions))) return; + + if (info) { + auto functor = std::bind( + std::mem_fn(&SurfaceViewPositionUpdater::doNotifyPositionLost), this, + (jlong) info->canvasContext.getFrameNumber()); + + info->canvasContext.enqueueFrameWork(std::move(functor)); + } else { + doNotifyPositionLost(0); + } + } + private: JNIEnv* jnienv() { JNIEnv* env; @@ -607,6 +622,21 @@ static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject, env->DeleteLocalRef(localref); } + void doNotifyPositionLost(jlong frameNumber) { + ATRACE_NAME("SurfaceView position lost"); + + JNIEnv* env = jnienv(); + jobject localref = env->NewLocalRef(mWeakRef); + if (CC_UNLIKELY(!localref)) { + jnienv()->DeleteWeakGlobalRef(mWeakRef); + mWeakRef = nullptr; + return; + } + + env->CallVoidMethod(localref, gSurfaceViewPositionLostMethod, frameNumber); + env->DeleteLocalRef(localref); + } + JavaVM* mVm; jobject mWeakRef; }; @@ -701,6 +731,8 @@ int register_android_view_RenderNode(JNIEnv* env) { jclass clazz = FindClassOrDie(env, "android/view/SurfaceView"); gSurfaceViewPositionUpdateMethod = GetMethodIDOrDie(env, clazz, "updateWindowPositionRT", "(JIIII)V"); + gSurfaceViewPositionLostMethod = GetMethodIDOrDie(env, clazz, + "windowPositionLostRT", "(J)V"); clazz = FindClassOrDie(env, "android/view/RenderNode"); gOnRenderNodeDetached = GetMethodIDOrDie(env, clazz, "onRenderNodeDetached", "()V"); diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index 5a3300ab8044..f8797bf63442 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -474,7 +474,7 @@ void RenderNode::applyLayerPropertiesToLayer(TreeInfo& info) { } #endif -void RenderNode::syncDisplayList(TreeObserver* observer) { +void RenderNode::syncDisplayList(TreeInfo* info) { // Make sure we inc first so that we don't fluctuate between 0 and 1, // which would thrash the layer cache if (mStagingDisplayList) { @@ -482,7 +482,7 @@ void RenderNode::syncDisplayList(TreeObserver* observer) { child->renderNode->incParentRefCount(); } } - deleteDisplayList(observer); + deleteDisplayList(info ? info->observer : nullptr, info); mDisplayList = mStagingDisplayList; mStagingDisplayList = nullptr; if (mDisplayList) { @@ -501,15 +501,15 @@ void RenderNode::pushStagingDisplayListChanges(TreeInfo& info) { // Damage with the old display list first then the new one to catch any // changes in isRenderable or, in the future, bounds damageSelf(info); - syncDisplayList(info.observer); + syncDisplayList(&info); damageSelf(info); } } -void RenderNode::deleteDisplayList(TreeObserver* observer) { +void RenderNode::deleteDisplayList(TreeObserver* observer, TreeInfo* info) { if (mDisplayList) { for (auto&& child : mDisplayList->getChildren()) { - child->renderNode->decParentRefCount(observer); + child->renderNode->decParentRefCount(observer, info); } } delete mDisplayList; @@ -541,35 +541,38 @@ void RenderNode::prepareSubTree(TreeInfo& info, bool functorsNeedLayer, DisplayL } } -void RenderNode::destroyHardwareResources(TreeObserver* observer) { +void RenderNode::destroyHardwareResources(TreeObserver* observer, TreeInfo* info) { if (mLayer) { destroyLayer(mLayer); mLayer = nullptr; } if (mDisplayList) { for (auto&& child : mDisplayList->getChildren()) { - child->renderNode->destroyHardwareResources(observer); + child->renderNode->destroyHardwareResources(observer, info); } if (mNeedsDisplayListSync) { // Next prepare tree we are going to push a new display list, so we can // drop our current one now - deleteDisplayList(observer); + deleteDisplayList(observer, info); } } } -void RenderNode::decParentRefCount(TreeObserver* observer) { +void RenderNode::decParentRefCount(TreeObserver* observer, TreeInfo* info) { LOG_ALWAYS_FATAL_IF(!mParentCount, "already 0!"); mParentCount--; if (!mParentCount) { if (observer) { observer->onMaybeRemovedFromTree(this); } + if (CC_UNLIKELY(mPositionListener.get())) { + mPositionListener->onPositionLost(*this, info); + } // If a child of ours is being attached to our parent then this will incorrectly // destroy its hardware resources. However, this situation is highly unlikely // and the failure is "just" that the layer is re-created, so this should // be safe enough - destroyHardwareResources(observer); + destroyHardwareResources(observer, info); } } diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index 5aecaa3b23e2..1eaf5d61d465 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -196,7 +196,7 @@ public: } ANDROID_API virtual void prepareTree(TreeInfo& info); - void destroyHardwareResources(TreeObserver* observer); + void destroyHardwareResources(TreeObserver* observer, TreeInfo* info = nullptr); // UI thread only! ANDROID_API void addAnimator(const sp<BaseRenderNodeAnimator>& animator); @@ -228,10 +228,19 @@ public: OffscreenBuffer** getLayerHandle() { return &mLayer; } // ugh... #endif + // Note: The position callbacks are relying on the listener using + // the frameNumber to appropriately batch/synchronize these transactions. + // There is no other filtering/batching to ensure that only the "final" + // state called once per frame. class ANDROID_API PositionListener { public: virtual ~PositionListener() {} + // Called when the RenderNode's position changes virtual void onPositionUpdated(RenderNode& node, const TreeInfo& info) = 0; + // Called when the RenderNode no longer has a position. As in, it's + // no longer being drawn. + // Note, tree info might be null + virtual void onPositionLost(RenderNode& node, const TreeInfo* info) = 0; }; // Note this is not thread safe, this needs to be called @@ -306,7 +315,7 @@ private: void syncProperties(); - void syncDisplayList(TreeObserver* observer); + void syncDisplayList(TreeInfo* info); void prepareTreeImpl(TreeInfo& info, bool functorsNeedLayer); void pushStagingPropertiesChanges(TreeInfo& info); @@ -317,11 +326,11 @@ private: #endif void prepareLayer(TreeInfo& info, uint32_t dirtyMask); void pushLayerUpdate(TreeInfo& info); - void deleteDisplayList(TreeObserver* observer); + void deleteDisplayList(TreeObserver* observer, TreeInfo* info = nullptr); void damageSelf(TreeInfo& info); void incParentRefCount() { mParentCount++; } - void decParentRefCount(TreeObserver* observer); + void decParentRefCount(TreeObserver* observer, TreeInfo* info = nullptr); String8 mName; sp<VirtualLightRefBase> mUserContext; |