Fix onTrimMemory for HardwareRenderer
Also fixes detachFunctor possibly drawing after return
Bug: 15189843
Bug: 15990672
Change-Id: I64c48cb674c461a8eeaba407b697e09f72c98ce3
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::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 @@
// 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..524ee62dd 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::stopDrawing() {
+ mRenderThread.removeFrameCallback(this);
+}
+
void CanvasContext::notifyFramePending() {
ATRACE_CALL();
mRenderThread.pushBackFrameCallback(this);
@@ -216,8 +223,6 @@
profiler().startFrame();
TreeInfo info(TreeInfo::MODE_RT_ONLY, mRenderThread.renderState());
- info.prepareTextures = false;
-
prepareTree(info);
if (info.out.canDrawThisFrame) {
draw();
@@ -241,10 +246,25 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
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);