From f7d9c1dc84671d4e99657ef071d275700d85bb11 Mon Sep 17 00:00:00 2001 From: John Reck Date: Wed, 9 Apr 2014 10:01:03 -0700 Subject: [PATCH] Fix ThreadedRenderer.setEnabled() Bug: 13914116 Fixes lifecycle issues around setEnabled where ThreadedRenderer was reporting as being enabled before it had a Surface. This is incorrect. Also fix some EGL lifecycle issues Change-Id: I12ebb279707f9b533a570b61d68735d858b560bf --- core/java/android/view/GLRenderer.java | 5 +++++ core/java/android/view/HardwareRenderer.java | 7 +++++++ core/java/android/view/ThreadedRenderer.java | 21 ++++++++++++++++++- core/java/android/view/ViewRootImpl.java | 6 ++++++ core/jni/android_view_ThreadedRenderer.cpp | 15 +++++++++++-- libs/hwui/renderthread/CanvasContext.cpp | 18 ++++++++++------ libs/hwui/renderthread/CanvasContext.h | 3 ++- libs/hwui/renderthread/RenderProxy.cpp | 22 +++++++++++++++----- libs/hwui/renderthread/RenderProxy.h | 5 +++-- 9 files changed, 85 insertions(+), 17 deletions(-) diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java index ad33b6f556612..bcdfda64b94a0 100644 --- a/core/java/android/view/GLRenderer.java +++ b/core/java/android/view/GLRenderer.java @@ -838,6 +838,11 @@ public class GLRenderer extends HardwareRenderer { } } + @Override + void pauseSurface(Surface surface) { + // No-op + } + boolean initializeEgl() { synchronized (sEglLock) { if (sEgl == null && sEglConfig == null) { diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index 92d85d19f3ebe..7d46cab7f677b 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -233,6 +233,13 @@ public abstract class HardwareRenderer { */ abstract void updateSurface(Surface surface) throws OutOfResourcesException; + /** + * Stops any 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 + */ + abstract void pauseSurface(Surface surface); + /** * Destroys all hardware rendering resources associated with the specified * view hierarchy. diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index a747ab601eabb..2e0f509087fea 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -54,27 +54,45 @@ public class ThreadedRenderer extends HardwareRenderer { private int mWidth, mHeight; private long mNativeProxy; + private boolean mInitialized = false; ThreadedRenderer(boolean translucent) { mNativeProxy = nCreateProxy(translucent); - setEnabled(mNativeProxy != 0); } @Override void destroy(boolean full) { + mInitialized = false; + updateEnabledState(null); nDestroyCanvas(mNativeProxy); } + private void updateEnabledState(Surface surface) { + if (surface == null || !surface.isValid()) { + setEnabled(false); + } else { + setEnabled(mInitialized); + } + } + @Override boolean initialize(Surface surface) throws OutOfResourcesException { + mInitialized = true; + updateEnabledState(surface); return nInitialize(mNativeProxy, surface); } @Override void updateSurface(Surface surface) throws OutOfResourcesException { + updateEnabledState(surface); nUpdateSurface(mNativeProxy, surface); } + @Override + void pauseSurface(Surface surface) { + nPauseSurface(mNativeProxy, surface); + } + @Override void destroyHardwareResources(View view) { destroyResources(view); @@ -267,6 +285,7 @@ public class ThreadedRenderer extends HardwareRenderer { private static native boolean nInitialize(long nativeProxy, Surface window); private static native void nUpdateSurface(long nativeProxy, Surface window); + private static native void nPauseSurface(long nativeProxy, Surface window); private static native void nSetup(long nativeProxy, int width, int height); private static native void nSetDisplayListData(long nativeProxy, long displayList, long newData); diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 94f0683b496cc..2d503bfa2c266 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -1421,6 +1421,12 @@ public final class ViewRootImpl implements ViewParent, host.getMeasuredHeight() + ", params=" + params); } + if (mAttachInfo.mHardwareRenderer != null) { + // relayoutWindow may decide to destroy mSurface. As that decision + // happens in WindowManager service, we need to be defensive here + // and stop using the surface in case it gets destroyed. + mAttachInfo.mHardwareRenderer.pauseSurface(mSurface); + } final int surfaceGenerationId = mSurface.getGenerationId(); relayoutResult = relayoutWindow(params, viewVisibility, insetsPending); if (!mDrawDuringWindowsAnimating && diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp index 32890cfee38fe..20a61bf2d3070 100644 --- a/core/jni/android_view_ThreadedRenderer.cpp +++ b/core/jni/android_view_ThreadedRenderer.cpp @@ -84,7 +84,7 @@ static jboolean android_view_ThreadedRenderer_initialize(JNIEnv* env, jobject cl jlong proxyPtr, jobject jsurface) { RenderProxy* proxy = reinterpret_cast(proxyPtr); sp window = android_view_Surface_getNativeWindow(env, jsurface); - return proxy->initialize(window.get()); + return proxy->initialize(window); } static void android_view_ThreadedRenderer_updateSurface(JNIEnv* env, jobject clazz, @@ -94,7 +94,17 @@ static void android_view_ThreadedRenderer_updateSurface(JNIEnv* env, jobject cla if (jsurface) { window = android_view_Surface_getNativeWindow(env, jsurface); } - proxy->updateSurface(window.get()); + proxy->updateSurface(window); +} + +static void android_view_ThreadedRenderer_pauseSurface(JNIEnv* env, jobject clazz, + jlong proxyPtr, jobject jsurface) { + RenderProxy* proxy = reinterpret_cast(proxyPtr); + sp window; + if (jsurface) { + window = android_view_Surface_getNativeWindow(env, jsurface); + } + proxy->pauseSurface(window); } static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz, @@ -203,6 +213,7 @@ static JNINativeMethod gMethods[] = { { "nDeleteProxy", "(J)V", (void*) android_view_ThreadedRenderer_deleteProxy }, { "nInitialize", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_initialize }, { "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface }, + { "nPauseSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_pauseSurface }, { "nSetup", "(JII)V", (void*) android_view_ThreadedRenderer_setup }, { "nSetDisplayListData", "(JJJ)V", (void*) android_view_ThreadedRenderer_setDisplayListData }, { "nDrawDisplayList", "(JJIIII)V", (void*) android_view_ThreadedRenderer_drawDisplayList }, diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index c231f6fbf00b7..af3534495658a 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -347,6 +347,7 @@ void CanvasContext::setSurface(EGLNativeWindowType window) { if (mEglSurface != EGL_NO_SURFACE) { mDirtyRegionsEnabled = mGlobalContext->enableDirtyRegions(mEglSurface); + mGlobalContext->makeCurrent(mEglSurface); mHaveNewSurface = true; } } @@ -356,14 +357,15 @@ void CanvasContext::swapBuffers() { mHaveNewSurface = false; } -void CanvasContext::makeCurrent() { +void CanvasContext::requireSurface() { + LOG_ALWAYS_FATAL_IF(mEglSurface == EGL_NO_SURFACE, + "requireSurface() called but no surface set!"); mGlobalContext->makeCurrent(mEglSurface); } bool CanvasContext::initialize(EGLNativeWindowType window) { if (mCanvas) return false; setSurface(window); - makeCurrent(); mCanvas = new OpenGLRenderer(); mCanvas->initProperties(); return true; @@ -371,7 +373,11 @@ bool CanvasContext::initialize(EGLNativeWindowType window) { void CanvasContext::updateSurface(EGLNativeWindowType window) { setSurface(window); - makeCurrent(); +} + +void CanvasContext::pauseSurface(EGLNativeWindowType window) { + // TODO: For now we just need a fence, in the future suspend any animations + // and such to prevent from trying to render into this surface } void CanvasContext::setup(int width, int height) { @@ -460,7 +466,7 @@ void CanvasContext::invokeFunctors() { if (!mCanvas) return; - makeCurrent(); + requireSurface(); Rect dirty; mCanvas->invokeFunctors(dirty); } @@ -491,12 +497,12 @@ void CanvasContext::runWithGlContext(RenderTask* task) { } Layer* CanvasContext::createRenderLayer(int width, int height) { - requireGlContext(); + requireSurface(); return LayerRenderer::createRenderLayer(width, height); } Layer* CanvasContext::createTextureLayer() { - requireGlContext(); + requireSurface(); return LayerRenderer::createTextureLayer(); } diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 6f1c37f3242a3..9f6494480dfa2 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -63,6 +63,7 @@ public: bool initialize(EGLNativeWindowType window); void updateSurface(EGLNativeWindowType window); + void pauseSurface(EGLNativeWindowType window); void setup(int width, int height); void setDisplayListData(RenderNode* displayList, DisplayListData* newData); void processLayerUpdates(const Vector* layerUpdaters); @@ -83,7 +84,7 @@ public: private: void setSurface(EGLNativeWindowType window); void swapBuffers(); - void makeCurrent(); + void requireSurface(); friend class InvokeFunctorsTask; void invokeFunctors(); diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index e817e616f016f..a7c955ed50d51 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -92,10 +92,10 @@ CREATE_BRIDGE2(initialize, CanvasContext* context, EGLNativeWindowType window) { return (void*) args->context->initialize(args->window); } -bool RenderProxy::initialize(EGLNativeWindowType window) { +bool RenderProxy::initialize(const sp& window) { SETUP_TASK(initialize); args->context = mContext; - args->window = window; + args->window = window.get(); return (bool) postAndWait(task); } @@ -104,11 +104,23 @@ CREATE_BRIDGE2(updateSurface, CanvasContext* context, EGLNativeWindowType window return NULL; } -void RenderProxy::updateSurface(EGLNativeWindowType window) { +void RenderProxy::updateSurface(const sp& window) { SETUP_TASK(updateSurface); args->context = mContext; - args->window = window; - post(task); + args->window = window.get(); + postAndWait(task); +} + +CREATE_BRIDGE2(pauseSurface, CanvasContext* context, EGLNativeWindowType window) { + args->context->pauseSurface(args->window); + return NULL; +} + +void RenderProxy::pauseSurface(const sp& window) { + SETUP_TASK(pauseSurface); + args->context = mContext; + args->window = window.get(); + postAndWait(task); } CREATE_BRIDGE3(setup, CanvasContext* context, int width, int height) { diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index c50da7976bb5d..489bf20c15286 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -59,8 +59,9 @@ public: ANDROID_API RenderProxy(bool translucent); ANDROID_API virtual ~RenderProxy(); - ANDROID_API bool initialize(EGLNativeWindowType window); - ANDROID_API void updateSurface(EGLNativeWindowType window); + ANDROID_API bool initialize(const sp& window); + ANDROID_API void updateSurface(const sp& window); + ANDROID_API void pauseSurface(const sp& window); ANDROID_API void setup(int width, int height); ANDROID_API void setDisplayListData(RenderNode* renderNode, DisplayListData* newData); ANDROID_API void drawDisplayList(RenderNode* displayList,