Merge "Move SurfaceView offscreen if the app stops drawing it" into nyc-mr1-dev

This commit is contained in:
John Reck
2016-06-17 20:13:19 +00:00
committed by Android (Google) Code Review
4 changed files with 102 additions and 31 deletions

View File

@@ -464,7 +464,8 @@ public class SurfaceView extends View {
|| mUpdateWindowNeeded || mReportDrawNeeded || redrawNeeded) { || mUpdateWindowNeeded || mReportDrawNeeded || redrawNeeded) {
getLocationInWindow(mLocation); 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 + " format=" + formatChanged + " size=" + sizeChanged
+ " visible=" + visibleChanged + " visible=" + visibleChanged
+ " left=" + (mWindowSpaceLeft != mLocation[0]) + " left=" + (mWindowSpaceLeft != mLocation[0])
@@ -534,7 +535,8 @@ public class SurfaceView extends View {
mReportDrawNeeded = false; mReportDrawNeeded = false;
mDrawingStopped = !visible; mDrawingStopped = !visible;
if (DEBUG) Log.i(TAG, "Cur surface: " + mSurface); if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ "Cur surface: " + mSurface);
relayoutResult = mSession.relayout( relayoutResult = mSession.relayout(
mWindow, mWindow.mSeq, mLayout, mWindowSpaceWidth, mWindowSpaceHeight, mWindow, mWindow.mSeq, mLayout, mWindowSpaceWidth, mWindowSpaceHeight,
@@ -547,7 +549,8 @@ public class SurfaceView extends View {
reportDrawNeeded = true; 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); + ", vis=" + visible + ", frame=" + mWinFrame);
mSurfaceFrame.left = 0; mSurfaceFrame.left = 0;
@@ -581,7 +584,8 @@ public class SurfaceView extends View {
if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) { if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
mSurfaceCreated = false; mSurfaceCreated = false;
if (mSurface.isValid()) { if (mSurface.isValid()) {
if (DEBUG) Log.i(TAG, "visibleChanged -- surfaceDestroyed"); if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ "visibleChanged -- surfaceDestroyed");
callbacks = getSurfaceCallbacks(); callbacks = getSurfaceCallbacks();
for (SurfaceHolder.Callback c : callbacks) { for (SurfaceHolder.Callback c : callbacks) {
c.surfaceDestroyed(mSurfaceHolder); c.surfaceDestroyed(mSurfaceHolder);
@@ -594,7 +598,8 @@ public class SurfaceView extends View {
if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) { if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
mSurfaceCreated = true; mSurfaceCreated = true;
mIsCreating = true; mIsCreating = true;
if (DEBUG) Log.i(TAG, "visibleChanged -- surfaceCreated"); if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ "visibleChanged -- surfaceCreated");
if (callbacks == null) { if (callbacks == null) {
callbacks = getSurfaceCallbacks(); callbacks = getSurfaceCallbacks();
} }
@@ -604,7 +609,8 @@ public class SurfaceView extends View {
} }
if (creating || formatChanged || sizeChanged if (creating || formatChanged || sizeChanged
|| visibleChanged || realSizeChanged) { || 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); + " w=" + myWidth + " h=" + myHeight);
if (callbacks == null) { if (callbacks == null) {
callbacks = getSurfaceCallbacks(); callbacks = getSurfaceCallbacks();
@@ -614,7 +620,8 @@ public class SurfaceView extends View {
} }
} }
if (redrawNeeded) { if (redrawNeeded) {
if (DEBUG) Log.i(TAG, "surfaceRedrawNeeded"); if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ "surfaceRedrawNeeded");
if (callbacks == null) { if (callbacks == null) {
callbacks = getSurfaceCallbacks(); callbacks = getSurfaceCallbacks();
} }
@@ -629,7 +636,8 @@ public class SurfaceView extends View {
} finally { } finally {
mIsCreating = false; mIsCreating = false;
if (redrawNeeded) { if (redrawNeeded) {
if (DEBUG) Log.i(TAG, "finishedDrawing"); if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ "finishedDrawing");
mSession.finishDrawing(mWindow); mSession.finishDrawing(mWindow);
} }
mSession.performDeferredDestroy(mWindow); mSession.performDeferredDestroy(mWindow);
@@ -663,8 +671,9 @@ public class SurfaceView extends View {
} }
try { try {
Log.d(TAG, String.format("updateWindowPosition UI, " + Log.d(TAG, String.format("%d updateWindowPosition UI, " +
"postion = [%d, %d, %d, %d]", mWinFrame.left, mWinFrame.top, "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
mWinFrame.left, mWinFrame.top,
mWinFrame.right, mWinFrame.bottom)); mWinFrame.right, mWinFrame.bottom));
mSession.repositionChild(mWindow, mWinFrame.left, mWinFrame.top, mSession.repositionChild(mWindow, mWinFrame.left, mWinFrame.top,
mWinFrame.right, mWinFrame.bottom, -1, mWinFrame); mWinFrame.right, mWinFrame.bottom, -1, mWinFrame);
@@ -697,9 +706,9 @@ public class SurfaceView extends View {
} }
try { try {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, String.format("updateWindowPosition RT, frameNr = %d, " + Log.d(TAG, String.format("%d updateWindowPosition RT, frameNr = %d, " +
"postion = [%d, %d, %d, %d]", frameNumber, left, top, "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
right, bottom)); frameNumber, left, top, right, bottom));
} }
// Just using mRTLastReportedPosition as a dummy rect here // Just using mRTLastReportedPosition as a dummy rect here
session.repositionChild(window, left, top, right, bottom, 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() { private SurfaceHolder.Callback[] getSurfaceCallbacks() {
SurfaceHolder.Callback callbacks[]; SurfaceHolder.Callback callbacks[];
synchronized (mCallbacks) { synchronized (mCallbacks) {
@@ -750,8 +778,7 @@ public class SurfaceView extends View {
boolean alwaysConsumeNavBar) { boolean alwaysConsumeNavBar) {
SurfaceView surfaceView = mSurfaceView.get(); SurfaceView surfaceView = mSurfaceView.get();
if (surfaceView != null) { if (surfaceView != null) {
if (DEBUG) Log.v( if (DEBUG) Log.v(TAG, surfaceView + " got resized: w=" + frame.width()
"SurfaceView", surfaceView + " got resized: w=" + frame.width()
+ " h=" + frame.height() + ", cur w=" + mCurWidth + " h=" + mCurHeight); + " h=" + frame.height() + ", cur w=" + mCurWidth + " h=" + mCurHeight);
surfaceView.mSurfaceLock.lock(); surfaceView.mSurfaceLock.lock();
try { try {
@@ -907,7 +934,7 @@ public class SurfaceView extends View {
private final Canvas internalLockCanvas(Rect dirty) { private final Canvas internalLockCanvas(Rect dirty) {
mSurfaceLock.lock(); mSurfaceLock.lock();
if (DEBUG) Log.i(TAG, "Locking canvas... stopped=" if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Locking canvas... stopped="
+ mDrawingStopped + ", win=" + mWindow); + mDrawingStopped + ", win=" + mWindow);
Canvas c = null; 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) { if (c != null) {
mLastLockTime = SystemClock.uptimeMillis(); mLastLockTime = SystemClock.uptimeMillis();
return c; return c;

View File

@@ -534,6 +534,7 @@ static void android_view_RenderNode_endAllAnimators(JNIEnv* env, jobject clazz,
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
jmethodID gSurfaceViewPositionUpdateMethod; jmethodID gSurfaceViewPositionUpdateMethod;
jmethodID gSurfaceViewPositionLostMethod;
static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject, static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject,
jlong renderNodePtr, jobject surfaceview) { jlong renderNodePtr, jobject surfaceview) {
@@ -581,6 +582,20 @@ static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject,
info.canvasContext.enqueueFrameWork(std::move(functor)); 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: private:
JNIEnv* jnienv() { JNIEnv* jnienv() {
JNIEnv* env; JNIEnv* env;
@@ -607,6 +622,21 @@ static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject,
env->DeleteLocalRef(localref); 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; JavaVM* mVm;
jobject mWeakRef; jobject mWeakRef;
}; };
@@ -701,6 +731,8 @@ int register_android_view_RenderNode(JNIEnv* env) {
jclass clazz = FindClassOrDie(env, "android/view/SurfaceView"); jclass clazz = FindClassOrDie(env, "android/view/SurfaceView");
gSurfaceViewPositionUpdateMethod = GetMethodIDOrDie(env, clazz, gSurfaceViewPositionUpdateMethod = GetMethodIDOrDie(env, clazz,
"updateWindowPositionRT", "(JIIII)V"); "updateWindowPositionRT", "(JIIII)V");
gSurfaceViewPositionLostMethod = GetMethodIDOrDie(env, clazz,
"windowPositionLostRT", "(J)V");
clazz = FindClassOrDie(env, "android/view/RenderNode"); clazz = FindClassOrDie(env, "android/view/RenderNode");
gOnRenderNodeDetached = GetMethodIDOrDie(env, clazz, gOnRenderNodeDetached = GetMethodIDOrDie(env, clazz,
"onRenderNodeDetached", "()V"); "onRenderNodeDetached", "()V");

View File

@@ -474,7 +474,7 @@ void RenderNode::applyLayerPropertiesToLayer(TreeInfo& info) {
} }
#endif #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, // Make sure we inc first so that we don't fluctuate between 0 and 1,
// which would thrash the layer cache // which would thrash the layer cache
if (mStagingDisplayList) { if (mStagingDisplayList) {
@@ -482,7 +482,7 @@ void RenderNode::syncDisplayList(TreeObserver* observer) {
child->renderNode->incParentRefCount(); child->renderNode->incParentRefCount();
} }
} }
deleteDisplayList(observer); deleteDisplayList(info ? info->observer : nullptr, info);
mDisplayList = mStagingDisplayList; mDisplayList = mStagingDisplayList;
mStagingDisplayList = nullptr; mStagingDisplayList = nullptr;
if (mDisplayList) { 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 // Damage with the old display list first then the new one to catch any
// changes in isRenderable or, in the future, bounds // changes in isRenderable or, in the future, bounds
damageSelf(info); damageSelf(info);
syncDisplayList(info.observer); syncDisplayList(&info);
damageSelf(info); damageSelf(info);
} }
} }
void RenderNode::deleteDisplayList(TreeObserver* observer) { void RenderNode::deleteDisplayList(TreeObserver* observer, TreeInfo* info) {
if (mDisplayList) { if (mDisplayList) {
for (auto&& child : mDisplayList->getChildren()) { for (auto&& child : mDisplayList->getChildren()) {
child->renderNode->decParentRefCount(observer); child->renderNode->decParentRefCount(observer, info);
} }
} }
delete mDisplayList; 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) { if (mLayer) {
destroyLayer(mLayer); destroyLayer(mLayer);
mLayer = nullptr; mLayer = nullptr;
} }
if (mDisplayList) { if (mDisplayList) {
for (auto&& child : mDisplayList->getChildren()) { for (auto&& child : mDisplayList->getChildren()) {
child->renderNode->destroyHardwareResources(observer); child->renderNode->destroyHardwareResources(observer, info);
} }
if (mNeedsDisplayListSync) { if (mNeedsDisplayListSync) {
// Next prepare tree we are going to push a new display list, so we can // Next prepare tree we are going to push a new display list, so we can
// drop our current one now // 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!"); LOG_ALWAYS_FATAL_IF(!mParentCount, "already 0!");
mParentCount--; mParentCount--;
if (!mParentCount) { if (!mParentCount) {
if (observer) { if (observer) {
observer->onMaybeRemovedFromTree(this); 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 // 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 // destroy its hardware resources. However, this situation is highly unlikely
// and the failure is "just" that the layer is re-created, so this should // and the failure is "just" that the layer is re-created, so this should
// be safe enough // be safe enough
destroyHardwareResources(observer); destroyHardwareResources(observer, info);
} }
} }

View File

@@ -196,7 +196,7 @@ public:
} }
ANDROID_API virtual void prepareTree(TreeInfo& info); ANDROID_API virtual void prepareTree(TreeInfo& info);
void destroyHardwareResources(TreeObserver* observer); void destroyHardwareResources(TreeObserver* observer, TreeInfo* info = nullptr);
// UI thread only! // UI thread only!
ANDROID_API void addAnimator(const sp<BaseRenderNodeAnimator>& animator); ANDROID_API void addAnimator(const sp<BaseRenderNodeAnimator>& animator);
@@ -228,10 +228,19 @@ public:
OffscreenBuffer** getLayerHandle() { return &mLayer; } // ugh... OffscreenBuffer** getLayerHandle() { return &mLayer; } // ugh...
#endif #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 { class ANDROID_API PositionListener {
public: public:
virtual ~PositionListener() {} virtual ~PositionListener() {}
// Called when the RenderNode's position changes
virtual void onPositionUpdated(RenderNode& node, const TreeInfo& info) = 0; 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 // Note this is not thread safe, this needs to be called
@@ -306,7 +315,7 @@ private:
void syncProperties(); void syncProperties();
void syncDisplayList(TreeObserver* observer); void syncDisplayList(TreeInfo* info);
void prepareTreeImpl(TreeInfo& info, bool functorsNeedLayer); void prepareTreeImpl(TreeInfo& info, bool functorsNeedLayer);
void pushStagingPropertiesChanges(TreeInfo& info); void pushStagingPropertiesChanges(TreeInfo& info);
@@ -317,11 +326,11 @@ private:
#endif #endif
void prepareLayer(TreeInfo& info, uint32_t dirtyMask); void prepareLayer(TreeInfo& info, uint32_t dirtyMask);
void pushLayerUpdate(TreeInfo& info); void pushLayerUpdate(TreeInfo& info);
void deleteDisplayList(TreeObserver* observer); void deleteDisplayList(TreeObserver* observer, TreeInfo* info = nullptr);
void damageSelf(TreeInfo& info); void damageSelf(TreeInfo& info);
void incParentRefCount() { mParentCount++; } void incParentRefCount() { mParentCount++; }
void decParentRefCount(TreeObserver* observer); void decParentRefCount(TreeObserver* observer, TreeInfo* info = nullptr);
String8 mName; String8 mName;
sp<VirtualLightRefBase> mUserContext; sp<VirtualLightRefBase> mUserContext;