diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index c4ed94f6184da..206ba1664407a 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -485,14 +485,24 @@ public final class ThreadedRenderer { } /** - * Stops any rendering into the surface. Use this if it is unclear whether + * Halts any current rendering into the surface. Use this if it is unclear whether * or not the surface used by the HardwareRenderer will be changing. It - * Suspends any rendering into the surface, but will not do any destruction + * Suspends any rendering into the surface, but will not do any destruction. + * + * Any subsequent draws will override the pause, resuming normal operation. */ boolean pauseSurface(Surface surface) { return nPauseSurface(mNativeProxy, surface); } + /** + * Hard stops or resumes rendering into the surface. This flag is used to + * determine whether or not it is safe to use the given surface *at all* + */ + void setStopped(boolean stopped) { + nSetStopped(mNativeProxy, stopped); + } + /** * Destroys all hardware rendering resources associated with the specified * view hierarchy. @@ -992,6 +1002,7 @@ public final class ThreadedRenderer { private static native void nInitialize(long nativeProxy, Surface window); private static native void nUpdateSurface(long nativeProxy, Surface window); private static native boolean nPauseSurface(long nativeProxy, Surface window); + private static native void nSetStopped(long nativeProxy, boolean stopped); private static native void nSetup(long nativeProxy, int width, int height, float lightRadius, int ambientShadowAlpha, int spotShadowAlpha); private static native void nSetLightCenter(long nativeProxy, diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 44b92e18144e3..b6d2160632f7f 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -1079,13 +1079,16 @@ public final class ViewRootImpl implements ViewParent, void setWindowStopped(boolean stopped) { if (mStopped != stopped) { mStopped = stopped; + final ThreadedRenderer renderer = mAttachInfo.mHardwareRenderer; + if (renderer != null) { + if (DEBUG_DRAW) Log.d(mTag, "WindowStopped on " + getTitle() + " set to " + mStopped); + renderer.setStopped(mStopped); + } if (!mStopped) { scheduleTraversals(); } else { - if (mAttachInfo.mHardwareRenderer != null) { - if (DEBUG_DRAW) Log.d(mTag, "WindowStopped on " + getTitle()); - mAttachInfo.mHardwareRenderer.updateSurface(null); - mAttachInfo.mHardwareRenderer.destroyHardwareResources(mView); + if (renderer != null) { + renderer.destroyHardwareResources(mView); } } } @@ -2555,6 +2558,7 @@ public final class ViewRootImpl implements ViewParent, if (mAttachInfo.mHardwareRenderer != null) { mAttachInfo.mHardwareRenderer.fence(); + mAttachInfo.mHardwareRenderer.setStopped(mStopped); } if (LOCAL_LOGV) { @@ -2704,6 +2708,13 @@ public final class ViewRootImpl implements ViewParent, // shortly before the draw commands get send to the renderer. final boolean updated = updateContentDrawBounds(); + if (mReportNextDraw) { + // report next draw overrides setStopped() + // This value is re-sync'd to the value of mStopped + // in the handling of mReportNextDraw post-draw. + mAttachInfo.mHardwareRenderer.setStopped(false); + } + mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this); if (updated) { diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp index faa41921ba118..68c818e92e5ca 100644 --- a/core/jni/android_view_ThreadedRenderer.cpp +++ b/core/jni/android_view_ThreadedRenderer.cpp @@ -479,6 +479,12 @@ static jboolean android_view_ThreadedRenderer_pauseSurface(JNIEnv* env, jobject return proxy->pauseSurface(surface); } +static void android_view_ThreadedRenderer_setStopped(JNIEnv* env, jobject clazz, + jlong proxyPtr, jboolean stopped) { + RenderProxy* proxy = reinterpret_cast(proxyPtr); + proxy->setStopped(stopped); +} + static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz, jlong proxyPtr, jint width, jint height, jfloat lightRadius, jint ambientShadowAlpha, jint spotShadowAlpha) { RenderProxy* proxy = reinterpret_cast(proxyPtr); @@ -740,6 +746,7 @@ static const JNINativeMethod gMethods[] = { { "nInitialize", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_initialize }, { "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface }, { "nPauseSurface", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_pauseSurface }, + { "nSetStopped", "(JZ)V", (void*) android_view_ThreadedRenderer_setStopped }, { "nSetup", "(JIIFII)V", (void*) android_view_ThreadedRenderer_setup }, { "nSetLightCenter", "(JFFF)V", (void*) android_view_ThreadedRenderer_setLightCenter }, { "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque }, diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index ab66b2aceb4c8..890d4a1ea2246 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -113,18 +113,11 @@ void CanvasContext::setSurface(Surface* surface) { mBufferPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer); mHaveNewSurface = true; mSwapHistory.clear(); - makeCurrent(); } else { mRenderThread.removeFrameCallback(this); } } -void CanvasContext::requireSurface() { - LOG_ALWAYS_FATAL_IF(mEglSurface == EGL_NO_SURFACE, - "requireSurface() called but no surface set!"); - makeCurrent(); -} - void CanvasContext::setSwapBehavior(SwapBehavior swapBehavior) { mSwapBehavior = swapBehavior; } @@ -146,6 +139,18 @@ bool CanvasContext::pauseSurface(Surface* surface) { return mRenderThread.removeFrameCallback(this); } +void CanvasContext::setStopped(bool stopped) { + if (mStopped != stopped) { + mStopped = stopped; + if (mStopped) { + mRenderThread.removeFrameCallback(this); + if (mEglManager.isCurrent(mEglSurface)) { + mEglManager.makeCurrent(EGL_NO_SURFACE); + } + } + } +} + // TODO: don't pass viewport size, it's automatic via EGL void CanvasContext::setup(int width, int height, float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) { @@ -172,7 +177,9 @@ void CanvasContext::setOpaque(bool opaque) { mOpaque = opaque; } -void CanvasContext::makeCurrent() { +bool CanvasContext::makeCurrent() { + if (mStopped) return false; + // TODO: Figure out why this workaround is needed, see b/13913604 // In the meantime this matches the behavior of GLRenderer, so it is not a regression EGLint error = 0; @@ -180,6 +187,7 @@ void CanvasContext::makeCurrent() { if (error) { setSurface(nullptr); } + return !error; } static bool wasSkipped(FrameInfo* info) { @@ -671,7 +679,7 @@ void CanvasContext::runWithGlContext(RenderTask* task) { } Layer* CanvasContext::createTextureLayer() { - requireSurface(); + mEglManager.initialize(); return LayerRenderer::createTextureLayer(mRenderThread.renderState()); } diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 9350114e1abcd..52df3abe2cae7 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -82,13 +82,14 @@ public: void initialize(Surface* surface); void updateSurface(Surface* surface); bool pauseSurface(Surface* surface); + void setStopped(bool stopped); bool hasSurface() { return mNativeSurface.get(); } void setup(int width, int height, float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha); void setLightCenter(const Vector3& lightCenter); void setOpaque(bool opaque); - void makeCurrent(); + bool makeCurrent(); void prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t syncQueued, RenderNode* target); void draw(); @@ -172,7 +173,6 @@ private: friend class android::uirenderer::RenderState; void setSurface(Surface* window); - void requireSurface(); void freePrefetchedLayers(TreeObserver* observer); @@ -185,6 +185,7 @@ private: EglManager& mEglManager; sp mNativeSurface; EGLSurface mEglSurface = EGL_NO_SURFACE; + bool mStopped = false; bool mBufferPreserved = false; SwapBehavior mSwapBehavior = kSwap_default; struct SwapHistory { diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp index 651aaa23e3410..ed472ac4bd02a 100644 --- a/libs/hwui/renderthread/DrawFrameTask.cpp +++ b/libs/hwui/renderthread/DrawFrameTask.cpp @@ -115,7 +115,7 @@ bool DrawFrameTask::syncFrameState(TreeInfo& info) { ATRACE_CALL(); int64_t vsync = mFrameInfo[static_cast(FrameInfoIndex::Vsync)]; mRenderThread->timeLord().vsyncReceived(vsync); - mContext->makeCurrent(); + bool canDraw = mContext->makeCurrent(); Caches::getInstance().textureCache.resetMarkInUse(mContext); for (size_t i = 0; i < mLayers.size(); i++) { @@ -126,8 +126,9 @@ bool DrawFrameTask::syncFrameState(TreeInfo& info) { // This is after the prepareTree so that any pending operations // (RenderNode tree state, prefetched layers, etc...) will be flushed. - if (CC_UNLIKELY(!mContext->hasSurface())) { + if (CC_UNLIKELY(!mContext->hasSurface() || !canDraw)) { mSyncResult |= kSync_LostSurfaceRewardIfFound; + info.out.canDrawThisFrame = false; } if (info.out.hasAnimations) { diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp index 8def7ad03d344..ac6a28fe62891 100644 --- a/libs/hwui/renderthread/EglManager.cpp +++ b/libs/hwui/renderthread/EglManager.cpp @@ -270,12 +270,6 @@ bool EglManager::makeCurrent(EGLSurface surface, EGLint* errOut) { // Ensure we always have a valid surface & context surface = mPBufferSurface; } - // TODO: Temporary to help diagnose b/27286867 - if (mCurrentSurface == mPBufferSurface || surface == mPBufferSurface) { - ALOGD("Switching from surface %p%s to %p%s", mCurrentSurface, - mCurrentSurface == mPBufferSurface ? " (pbuffer)" : "", - surface, surface == mPBufferSurface ? " (pbuffer)" : ""); - } if (!eglMakeCurrent(mEglDisplay, surface, surface, mEglContext)) { if (errOut) { *errOut = eglGetError(); diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 096093caff515..5e37856ecce9a 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -168,6 +168,18 @@ bool RenderProxy::pauseSurface(const sp& surface) { return (bool) postAndWait(task); } +CREATE_BRIDGE2(setStopped, CanvasContext* context, bool stopped) { + args->context->setStopped(args->stopped); + return nullptr; +} + +void RenderProxy::setStopped(bool stopped) { + SETUP_TASK(setStopped); + args->context = mContext; + args->stopped = stopped; + postAndWait(task); +} + CREATE_BRIDGE6(setup, CanvasContext* context, int width, int height, float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) { args->context->setup(args->width, args->height, args->lightRadius, diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index 98aace0da6b59..c39319da4b395 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -79,6 +79,7 @@ public: ANDROID_API void initialize(const sp& surface); ANDROID_API void updateSurface(const sp& surface); ANDROID_API bool pauseSurface(const sp& surface); + ANDROID_API void setStopped(bool stopped); ANDROID_API void setup(int width, int height, float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha); ANDROID_API void setLightCenter(const Vector3& lightCenter);