diff options
author | John Reck <jreck@google.com> | 2014-06-30 16:20:04 -0700 |
---|---|---|
committer | John Reck <jreck@google.com> | 2014-06-30 16:36:26 -0700 |
commit | f47a594f5250b1914c36423ee6b371f0b8db09d0 (patch) | |
tree | f86289c7b515c2111fde3ce11e7fca384bc2f603 | |
parent | dd59aba6c7e142eae14d5f29ea6873a5b9790174 (diff) | |
download | frameworks_base-f47a594f5250b1914c36423ee6b371f0b8db09d0.zip frameworks_base-f47a594f5250b1914c36423ee6b371f0b8db09d0.tar.gz frameworks_base-f47a594f5250b1914c36423ee6b371f0b8db09d0.tar.bz2 |
Fix onTrimMemory for HardwareRenderer
Also fixes detachFunctor possibly drawing after return
Bug: 15189843
Bug: 15990672
Change-Id: I64c48cb674c461a8eeaba407b697e09f72c98ce3
-rw-r--r-- | core/java/android/app/ActivityThread.java | 9 | ||||
-rw-r--r-- | core/java/android/view/GLES20Canvas.java | 25 | ||||
-rw-r--r-- | core/java/android/view/HardwareRenderer.java | 40 | ||||
-rw-r--r-- | core/java/android/view/ThreadedRenderer.java | 21 | ||||
-rw-r--r-- | core/java/android/view/View.java | 4 | ||||
-rw-r--r-- | core/java/android/view/ViewRootImpl.java | 14 | ||||
-rw-r--r-- | core/java/android/view/WindowManagerGlobal.java | 46 | ||||
-rw-r--r-- | core/jni/android_view_ThreadedRenderer.cpp | 21 | ||||
-rw-r--r-- | libs/hwui/RenderNode.cpp | 19 | ||||
-rw-r--r-- | libs/hwui/TreeInfo.h | 3 | ||||
-rw-r--r-- | libs/hwui/renderthread/CanvasContext.cpp | 34 | ||||
-rw-r--r-- | libs/hwui/renderthread/CanvasContext.h | 4 | ||||
-rw-r--r-- | libs/hwui/renderthread/RenderProxy.cpp | 33 | ||||
-rw-r--r-- | libs/hwui/renderthread/RenderProxy.h | 4 | ||||
-rw-r--r-- | opengl/java/android/opengl/ManagedEGLContext.java | 137 |
15 files changed, 142 insertions, 272 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index f5514f8..422d88c 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -3962,10 +3962,6 @@ public final class ActivityThread { ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(false, config); - // Cleanup hardware accelerated stuff - // TODO: Do we actually want to do this in response to all config changes? - WindowManagerGlobal.getInstance().trimLocalMemory(); - freeTextLayoutCachesIfNeeded(configDiff); if (callbacks != null) { @@ -4100,9 +4096,6 @@ public final class ActivityThread { final void handleTrimMemory(int level) { if (DEBUG_MEMORY_TRIM) Slog.v(TAG, "Trimming memory to level: " + level); - final WindowManagerGlobal windowManager = WindowManagerGlobal.getInstance(); - windowManager.startTrimMemory(level); - ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(true, null); final int N = callbacks.size(); @@ -4110,7 +4103,7 @@ public final class ActivityThread { callbacks.get(i).onTrimMemory(level); } - windowManager.endTrimMemory(); + WindowManagerGlobal.getInstance().trimMemory(level); } private void setupGraphicsSupport(LoadedApk info, File cacheDir) { diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index dcd9ba9..d7d3c72 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -203,31 +203,6 @@ class GLES20Canvas extends HardwareCanvas { private static native int nCallDrawGLFunction(long renderer, long drawGLFunction); /////////////////////////////////////////////////////////////////////////// - // Memory - /////////////////////////////////////////////////////////////////////////// - - /** - * Must match Caches::FlushMode values - * - * @see #flushCaches(int) - */ - static final int FLUSH_CACHES_LAYERS = 0; - - /** - * Must match Caches::FlushMode values - * - * @see #flushCaches(int) - */ - static final int FLUSH_CACHES_MODERATE = 1; - - /** - * Must match Caches::FlushMode values - * - * @see #flushCaches(int) - */ - static final int FLUSH_CACHES_FULL = 2; - - /////////////////////////////////////////////////////////////////////////// // Display list /////////////////////////////////////////////////////////////////////////// diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index e9bdcae..d69d01d 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -18,8 +18,6 @@ package android.view; import android.content.Context; import android.graphics.Bitmap; -import android.graphics.Rect; -import android.graphics.SurfaceTexture; import android.util.DisplayMetrics; import android.view.Surface.OutOfResourcesException; @@ -200,10 +198,8 @@ public abstract class HardwareRenderer { /** * Destroys the hardware rendering context. - * - * @param full If true, destroys all associated resources. */ - abstract void destroy(boolean full); + abstract void destroy(); /** * Initializes the hardware renderer for the specified surface. @@ -435,28 +431,7 @@ public abstract class HardwareRenderer { * see {@link android.content.ComponentCallbacks} */ static void trimMemory(int level) { - startTrimMemory(level); - endTrimMemory(); - } - - /** - * Starts the process of trimming memory. Usually this call will setup - * hardware rendering context and reclaim memory.Extra cleanup might - * be required by calling {@link #endTrimMemory()}. - * - * @param level Hint about the amount of memory that should be trimmed, - * see {@link android.content.ComponentCallbacks} - */ - static void startTrimMemory(int level) { - ThreadedRenderer.startTrimMemory(level); - } - - /** - * Finishes the process of trimming memory. This method will usually - * cleanup special resources used by the memory trimming process. - */ - static void endTrimMemory() { - ThreadedRenderer.endTrimMemory(); + ThreadedRenderer.trimMemory(level); } /** @@ -503,8 +478,15 @@ public abstract class HardwareRenderer { abstract void fence(); /** + * Prevents any further drawing until draw() is called. This is a signal + * that the contents of the RenderNode tree are no longer safe to play back. + * In practice this usually means that there are Functor pointers in the + * display list that are no longer valid. + */ + abstract void stopDrawing(); + + /** * Called by {@link ViewRootImpl} when a new performTraverals is scheduled. */ - public void notifyFramePending() { - } + abstract void notifyFramePending(); } diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index 45714ff..fcc51ec 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -90,7 +90,7 @@ public class ThreadedRenderer extends HardwareRenderer { } @Override - void destroy(boolean full) { + void destroy() { mInitialized = false; updateEnabledState(null); nDestroyCanvasAndSurface(mNativeProxy); @@ -125,7 +125,7 @@ public class ThreadedRenderer extends HardwareRenderer { @Override void destroyHardwareResources(View view) { destroyResources(view); - nFlushCaches(mNativeProxy, GLES20Canvas.FLUSH_CACHES_LAYERS); + nDestroyHardwareResources(mNativeProxy); } private static void destroyResources(View view) { @@ -289,6 +289,11 @@ public class ThreadedRenderer extends HardwareRenderer { } @Override + void stopDrawing() { + nStopDrawing(mNativeProxy); + } + + @Override public void notifyFramePending() { nNotifyFramePending(mNativeProxy); } @@ -303,12 +308,8 @@ public class ThreadedRenderer extends HardwareRenderer { } } - static void startTrimMemory(int level) { - // TODO - } - - static void endTrimMemory() { - // TODO + static void trimMemory(int level) { + nTrimMemory(level); } private static class AtlasInitializer { @@ -403,9 +404,11 @@ public class ThreadedRenderer extends HardwareRenderer { private static native void nCancelLayerUpdate(long nativeProxy, long layer); private static native void nDetachSurfaceTexture(long nativeProxy, long layer); - private static native void nFlushCaches(long nativeProxy, int flushMode); + private static native void nDestroyHardwareResources(long nativeProxy); + private static native void nTrimMemory(int level); private static native void nFence(long nativeProxy); + private static native void nStopDrawing(long nativeProxy); private static native void nNotifyFramePending(long nativeProxy); private static native void nDumpProfileInfo(long nativeProxy, FileDescriptor fd); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 829e089..6cfc019 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -13598,7 +13598,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @hide */ protected void destroyHardwareResources() { - resetDisplayList(); + // Intentionally empty. RenderNode's lifecycle is now fully managed + // by the hardware renderer. + // However some subclasses (eg, WebView, TextureView) still need this signal } /** diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 4c9d3f9..3219330 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -632,21 +632,17 @@ public final class ViewRootImpl implements ViewParent, void destroyHardwareResources() { if (mAttachInfo.mHardwareRenderer != null) { mAttachInfo.mHardwareRenderer.destroyHardwareResources(mView); - mAttachInfo.mHardwareRenderer.destroy(false); + mAttachInfo.mHardwareRenderer.destroy(); } } - void destroyHardwareLayers() { - // TODO Implement - } - public void detachFunctor(long functor) { // TODO: Make the resize buffer some other way to not need this block mBlockResizeBuffer = true; if (mAttachInfo.mHardwareRenderer != null) { // Fence so that any pending invokeFunctor() messages will be processed // before we return from detachFunctor. - mAttachInfo.mHardwareRenderer.fence(); + mAttachInfo.mHardwareRenderer.stopDrawing(); } } @@ -696,7 +692,7 @@ public final class ViewRootImpl implements ViewParent, if (!HardwareRenderer.sRendererDisabled || (HardwareRenderer.sSystemRendererDisabled && forceHwAccelerated)) { if (mAttachInfo.mHardwareRenderer != null) { - mAttachInfo.mHardwareRenderer.destroy(true); + mAttachInfo.mHardwareRenderer.destroy(); } final boolean translucent = attrs.format != PixelFormat.OPAQUE; @@ -1613,7 +1609,7 @@ public final class ViewRootImpl implements ViewParent, // Our surface is gone if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) { - mAttachInfo.mHardwareRenderer.destroy(true); + mAttachInfo.mHardwareRenderer.destroy(); } } else if (surfaceGenerationId != mSurface.getGenerationId() && mSurfaceHolder == null && mAttachInfo.mHardwareRenderer != null) { @@ -5436,7 +5432,7 @@ public final class ViewRootImpl implements ViewParent, if (mView != null) { hardwareRenderer.destroyHardwareResources(mView); } - hardwareRenderer.destroy(true); + hardwareRenderer.destroy(); hardwareRenderer.setRequested(false); attachInfo.mHardwareRenderer = null; diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java index 0ebf2e1..74bc186 100644 --- a/core/java/android/view/WindowManagerGlobal.java +++ b/core/java/android/view/WindowManagerGlobal.java @@ -20,7 +20,6 @@ import android.animation.ValueAnimator; import android.app.ActivityManager; import android.content.ComponentCallbacks2; import android.content.res.Configuration; -import android.opengl.ManagedEGLContext; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; @@ -114,7 +113,6 @@ public final class WindowManagerGlobal { private final ArrayList<WindowManager.LayoutParams> mParams = new ArrayList<WindowManager.LayoutParams>(); private final ArraySet<View> mDyingViews = new ArraySet<View>(); - private boolean mNeedsEglTerminate; private Runnable mSystemPropertyUpdater; @@ -377,13 +375,22 @@ public final class WindowManagerGlobal { return index; } - public void startTrimMemory(int level) { + public static boolean shouldDestroyEglContext(int trimLevel) { + // On low-end gfx devices we trim when memory is moderate; + // on high-end devices we do this when low. + if (trimLevel >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) { + return true; + } + if (trimLevel >= ComponentCallbacks2.TRIM_MEMORY_MODERATE + && !ActivityManager.isHighEndGfx()) { + return true; + } + return false; + } + + public void trimMemory(int level) { if (HardwareRenderer.isAvailable()) { - // On low-end gfx devices we trim when memory is moderate; - // on high-end devices we do this when low. - if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE - || (level >= ComponentCallbacks2.TRIM_MEMORY_MODERATE - && !ActivityManager.isHighEndGfx())) { + if (shouldDestroyEglContext(level)) { // Destroy all hardware surfaces and resources associated to // known windows synchronized (mLock) { @@ -392,29 +399,10 @@ public final class WindowManagerGlobal { } } // Force a full memory flush - mNeedsEglTerminate = true; - HardwareRenderer.startTrimMemory(ComponentCallbacks2.TRIM_MEMORY_COMPLETE); - return; + level = ComponentCallbacks2.TRIM_MEMORY_COMPLETE; } - HardwareRenderer.startTrimMemory(level); - } - } - - public void endTrimMemory() { - HardwareRenderer.endTrimMemory(); - - if (mNeedsEglTerminate) { - ManagedEGLContext.doTerminate(); - mNeedsEglTerminate = false; - } - } - - public void trimLocalMemory() { - synchronized (mLock) { - for (int i = mRoots.size() - 1; i >= 0; --i) { - mRoots.get(i).destroyHardwareLayers(); - } + HardwareRenderer.trimMemory(level); } } diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp index e63c475..aab48b3 100644 --- a/core/jni/android_view_ThreadedRenderer.cpp +++ b/core/jni/android_view_ThreadedRenderer.cpp @@ -298,10 +298,15 @@ static void android_view_ThreadedRenderer_detachSurfaceTexture(JNIEnv* env, jobj proxy->detachSurfaceTexture(layer); } -static void android_view_ThreadedRenderer_flushCaches(JNIEnv* env, jobject clazz, - jlong proxyPtr, jint flushMode) { +static void android_view_ThreadedRenderer_destroyHardwareResources(JNIEnv* env, jobject clazz, + jlong proxyPtr) { RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); - proxy->flushCaches(static_cast<Caches::FlushMode>(flushMode)); + proxy->destroyHardwareResources(); +} + +static void android_view_ThreadedRenderer_trimMemory(JNIEnv* env, jobject clazz, + jint level) { + RenderProxy::trimMemory(level); } static void android_view_ThreadedRenderer_fence(JNIEnv* env, jobject clazz, @@ -310,6 +315,12 @@ static void android_view_ThreadedRenderer_fence(JNIEnv* env, jobject clazz, proxy->fence(); } +static void android_view_ThreadedRenderer_stopDrawing(JNIEnv* env, jobject clazz, + jlong proxyPtr) { + RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); + proxy->stopDrawing(); +} + static void android_view_ThreadedRenderer_notifyFramePending(JNIEnv* env, jobject clazz, jlong proxyPtr) { RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); @@ -365,8 +376,10 @@ static JNINativeMethod gMethods[] = { { "nPushLayerUpdate", "(JJ)V", (void*) android_view_ThreadedRenderer_pushLayerUpdate }, { "nCancelLayerUpdate", "(JJ)V", (void*) android_view_ThreadedRenderer_cancelLayerUpdate }, { "nDetachSurfaceTexture", "(JJ)V", (void*) android_view_ThreadedRenderer_detachSurfaceTexture }, - { "nFlushCaches", "(JI)V", (void*) android_view_ThreadedRenderer_flushCaches }, + { "nDestroyHardwareResources", "(J)V", (void*) android_view_ThreadedRenderer_destroyHardwareResources }, + { "nTrimMemory", "(I)V", (void*) android_view_ThreadedRenderer_trimMemory }, { "nFence", "(J)V", (void*) android_view_ThreadedRenderer_fence }, + { "nStopDrawing", "(J)V", (void*) android_view_ThreadedRenderer_stopDrawing }, { "nNotifyFramePending", "(J)V", (void*) android_view_ThreadedRenderer_notifyFramePending }, { "nDumpProfileInfo", "(JLjava/io/FileDescriptor;)V", (void*) android_view_ThreadedRenderer_dumpProfileInfo }, #endif diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index e803ec3..89105ea 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -195,17 +195,28 @@ void RenderNode::pushLayerUpdate(TreeInfo& info) { void RenderNode::prepareTreeImpl(TreeInfo& info) { info.damageAccumulator->pushTransform(this); - if (info.mode == TreeInfo::MODE_FULL) { + + switch (info.mode) { + case TreeInfo::MODE_FULL: pushStagingPropertiesChanges(info); mAnimatorManager.animate(info); - } else if (info.mode == TreeInfo::MODE_MAYBE_DETACHING) { + break; + case TreeInfo::MODE_MAYBE_DETACHING: pushStagingPropertiesChanges(info); - } else if (info.mode == TreeInfo::MODE_RT_ONLY) { + break; + case TreeInfo::MODE_RT_ONLY: mAnimatorManager.animate(info); + break; + case TreeInfo::MODE_DESTROY_RESOURCES: + // This will also release the hardware layer if we have one as + // isRenderable() will return false, thus causing pushLayerUpdate + // to recycle the hardware layer + setStagingDisplayList(NULL); + break; } prepareLayer(info); - if (info.mode == TreeInfo::MODE_FULL) { + if (info.mode == TreeInfo::MODE_FULL || info.mode == TreeInfo::MODE_DESTROY_RESOURCES) { pushStagingDisplayListChanges(info); } prepareSubTree(info, mDisplayListData); diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h index 083100e..9746ac53 100644 --- a/libs/hwui/TreeInfo.h +++ b/libs/hwui/TreeInfo.h @@ -65,7 +65,8 @@ public: // but don't evaluate animators and such as if it isn't detached as a // MODE_FULL will follow shortly. MODE_MAYBE_DETACHING, - // TODO: TRIM_MEMORY? + // Destroy all hardware resources, including DisplayListData, in the tree. + MODE_DESTROY_RESOURCES, }; explicit TreeInfo(TraversalMode mode, RenderState& renderState) diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 9c3cf44..524ee62 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -30,6 +30,9 @@ #include "../OpenGLRenderer.h" #include "../Stencil.h" +#define TRIM_MEMORY_COMPLETE 80 +#define TRIM_MEMORY_UI_HIDDEN 20 + namespace android { namespace uirenderer { namespace renderthread { @@ -156,6 +159,10 @@ void CanvasContext::prepareTree(TreeInfo& info) { } } +void CanvasContext::stopDrawing() { + mRenderThread.removeFrameCallback(this); +} + void CanvasContext::notifyFramePending() { ATRACE_CALL(); mRenderThread.pushBackFrameCallback(this); @@ -216,8 +223,6 @@ void CanvasContext::doFrame() { profiler().startFrame(); TreeInfo info(TreeInfo::MODE_RT_ONLY, mRenderThread.renderState()); - info.prepareTextures = false; - prepareTree(info); if (info.out.canDrawThisFrame) { draw(); @@ -241,10 +246,25 @@ bool CanvasContext::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) return LayerRenderer::copyLayer(mRenderThread.renderState(), layer->backingLayer(), bitmap); } -void CanvasContext::flushCaches(Caches::FlushMode flushMode) { +void CanvasContext::destroyHardwareResources() { + stopDrawing(); if (mEglManager.hasEglContext()) { requireGlContext(); - Caches::getInstance().flush(flushMode); + TreeInfo info(TreeInfo::MODE_DESTROY_RESOURCES, mRenderThread.renderState()); + mRootRenderNode->prepareTree(info); + Caches::getInstance().flush(Caches::kFlushMode_Layers); + } +} + +void CanvasContext::trimMemory(RenderThread& thread, int level) { + // No context means nothing to free + if (!thread.eglManager().hasEglContext()) return; + + if (level >= TRIM_MEMORY_COMPLETE) { + Caches::getInstance().flush(Caches::kFlushMode_Full); + thread.eglManager().destroy(); + } else if (level >= TRIM_MEMORY_UI_HIDDEN) { + Caches::getInstance().flush(Caches::kFlushMode_Moderate); } } @@ -264,11 +284,7 @@ Layer* CanvasContext::createTextureLayer() { } void CanvasContext::requireGlContext() { - if (mEglSurface != EGL_NO_SURFACE) { - makeCurrent(); - } else { - mEglManager.usePBufferSurface(); - } + mEglManager.requireGlContext(); } void CanvasContext::setTextureAtlas(RenderThread& thread, diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index dbfb3d2..1bab1b1 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -66,7 +66,8 @@ public: bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap); - void flushCaches(Caches::FlushMode flushMode); + void destroyHardwareResources(); + static void trimMemory(RenderThread& thread, int level); static void invokeFunctor(RenderThread& thread, Functor* functor); @@ -78,6 +79,7 @@ public: ANDROID_API static void setTextureAtlas(RenderThread& thread, const sp<GraphicBuffer>& buffer, int64_t* map, size_t mapSize); + void stopDrawing(); void notifyFramePending(); DrawProfiler& profiler() { return mProfiler; } diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index e1ee620..6cd3d0b 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -312,18 +312,30 @@ void RenderProxy::detachSurfaceTexture(DeferredLayerUpdater* layer) { postAndWait(task); } -CREATE_BRIDGE2(flushCaches, CanvasContext* context, Caches::FlushMode flushMode) { - args->context->flushCaches(args->flushMode); +CREATE_BRIDGE1(destroyHardwareResources, CanvasContext* context) { + args->context->destroyHardwareResources(); return NULL; } -void RenderProxy::flushCaches(Caches::FlushMode flushMode) { - SETUP_TASK(flushCaches); +void RenderProxy::destroyHardwareResources() { + SETUP_TASK(destroyHardwareResources); args->context = mContext; - args->flushMode = flushMode; post(task); } +CREATE_BRIDGE2(timMemory, RenderThread* thread, int level) { + CanvasContext::trimMemory(*args->thread, args->level); + return NULL; +} + +void RenderProxy::trimMemory(int level) { + RenderThread& thread = RenderThread::getInstance(); + SETUP_TASK(timMemory); + args->thread = &thread; + args->level = level; + thread.queue(task); +} + CREATE_BRIDGE0(fence) { // Intentionally empty return NULL; @@ -334,6 +346,17 @@ void RenderProxy::fence() { postAndWait(task); } +CREATE_BRIDGE1(stopDrawing, CanvasContext* context) { + args->context->stopDrawing(); + return NULL; +} + +void RenderProxy::stopDrawing() { + SETUP_TASK(stopDrawing); + args->context = mContext; + postAndWait(task); +} + CREATE_BRIDGE1(notifyFramePending, CanvasContext* context) { args->context->notifyFramePending(); return NULL; diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index c7358e6..0027403 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -85,9 +85,11 @@ public: ANDROID_API void cancelLayerUpdate(DeferredLayerUpdater* layer); ANDROID_API void detachSurfaceTexture(DeferredLayerUpdater* layer); - ANDROID_API void flushCaches(Caches::FlushMode flushMode); + ANDROID_API void destroyHardwareResources(); + ANDROID_API static void trimMemory(int level); ANDROID_API void fence(); + ANDROID_API void stopDrawing(); ANDROID_API void notifyFramePending(); ANDROID_API void dumpProfileInfo(int fd); diff --git a/opengl/java/android/opengl/ManagedEGLContext.java b/opengl/java/android/opengl/ManagedEGLContext.java deleted file mode 100644 index 61fa565..0000000 --- a/opengl/java/android/opengl/ManagedEGLContext.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -package android.opengl; - -import static javax.microedition.khronos.egl.EGL10.EGL_DEFAULT_DISPLAY; -import static javax.microedition.khronos.egl.EGL10.EGL_NO_DISPLAY; - -import java.util.ArrayList; - -import javax.microedition.khronos.egl.EGL10; -import javax.microedition.khronos.egl.EGLContext; -import javax.microedition.khronos.egl.EGLDisplay; - -import android.os.Looper; -import android.util.Log; - -import com.google.android.gles_jni.EGLImpl; - -/** - * The per-process memory overhead of hardware accelerated graphics can - * be quite large on some devices. For small memory devices, being able to - * terminate all EGL contexts so that this graphics driver memory can be - * reclaimed can significant improve the overall behavior of the device. This - * class helps app developers participate in releasing their EGL context - * when appropriate and possible. - * - * <p>To use, simple instantiate this class with the EGLContext you create. - * When you have done this, if the device is getting low on memory and all - * of the currently created EGL contexts in the process are being managed - * through this class, then they will all be asked to terminate through the - * call to {@link #onTerminate}. - * - * @hide - */ -public abstract class ManagedEGLContext { - static final String TAG = "ManagedEGLContext"; - - static final ArrayList<ManagedEGLContext> sActive = new ArrayList<ManagedEGLContext>(); - - final EGLContext mContext; - - /** - * Instantiate to manage the given EGLContext. - */ - public ManagedEGLContext(EGLContext context) { - mContext = context; - synchronized (sActive) { - sActive.add(this); - } - } - - /** - * Retrieve the EGLContext being managed by the class. - */ - public EGLContext getContext() { - return mContext; - } - - /** - * Force-terminate the ManagedEGLContext. This will cause - * {@link #onTerminate(EGLContext)} to be called. You <em>must</em> - * call this when destroying the EGLContext, so that the framework - * knows to stop managing it. - */ - public void terminate() { - execTerminate(); - } - - void execTerminate() { - onTerminate(mContext); - } - - /** - * Override this method to destroy the EGLContext when appropriate. - * <em>Note that this method is always called on the main thread - * of the process.</em> If your EGLContext was created on a different - * thread, you will need to implement this method to hand off the work - * of destroying the context to that thread. - */ - public abstract void onTerminate(EGLContext context); - - /** @hide */ - public static boolean doTerminate() { - ArrayList<ManagedEGLContext> active; - - if (Looper.getMainLooper() != Looper.myLooper()) { - throw new IllegalStateException("Called on wrong thread"); - } - - synchronized (sActive) { - // If there are no active managed contexts, we will not even - // try to terminate. - if (sActive.size() <= 0) { - return false; - } - - // Need to check how many EGL contexts are actually running, - // to compare with how many we are managing. - EGL10 egl = (EGL10) EGLContext.getEGL(); - EGLDisplay display = egl.eglGetDisplay(EGL_DEFAULT_DISPLAY); - - if (display == EGL_NO_DISPLAY) { - Log.w(TAG, "doTerminate failed: no display"); - return false; - } - - if (EGLImpl.getInitCount(display) != sActive.size()) { - Log.w(TAG, "doTerminate failed: EGL count is " + EGLImpl.getInitCount(display) - + " but managed count is " + sActive.size()); - return false; - } - - active = new ArrayList<ManagedEGLContext>(sActive); - sActive.clear(); - } - - for (int i = 0; i < active.size(); i++) { - active.get(i).execTerminate(); - } - - return true; - } -} |