Overhaul RenderNode's DisplayList management
* Move mValid to native
* Have destroyHardwareResources destroy everything
* Remove flaky mParentCount checks in setStaging
* All tree updates have an internal observer to
ensure onRemovedFromTree() is a reliable signal
* onRemovedFromTree() immediately releases resources
to avoid displaylist "leaks"
Test: Unit tests for validity added & pass, manually
verified that b/34072929 doesn't repro
Bug: 34072929
Change-Id: I856534b4ed1b7f009fc4b7cd13209b97fa42a71c
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 1b3bf96..a53e5e0 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -146,21 +146,38 @@
, mProfiler(mFrames)
, mContentDrawBounds(0, 0, 0, 0)
, mRenderPipeline(std::move(renderPipeline)) {
+ rootRenderNode->makeRoot();
mRenderNodes.emplace_back(rootRenderNode);
mRenderThread.renderState().registerCanvasContext(this);
mProfiler.setDensity(mRenderThread.mainDisplayInfo().density);
}
CanvasContext::~CanvasContext() {
- destroy(nullptr);
+ destroy();
mRenderThread.renderState().unregisterCanvasContext(this);
+ for (auto& node : mRenderNodes) {
+ node->clearRoot();
+ }
+ mRenderNodes.clear();
}
-void CanvasContext::destroy(TreeObserver* observer) {
+void CanvasContext::addRenderNode(RenderNode* node, bool placeFront) {
+ int pos = placeFront ? 0 : static_cast<int>(mRenderNodes.size());
+ node->makeRoot();
+ mRenderNodes.emplace(mRenderNodes.begin() + pos, node);
+}
+
+void CanvasContext::removeRenderNode(RenderNode* node) {
+ node->clearRoot();
+ mRenderNodes.erase(std::remove(mRenderNodes.begin(), mRenderNodes.end(), node),
+ mRenderNodes.end());
+}
+
+void CanvasContext::destroy() {
stopDrawing();
setSurface(nullptr);
- freePrefetchedLayers(observer);
- destroyHardwareResources(observer);
+ freePrefetchedLayers();
+ destroyHardwareResources();
mAnimationContext->destroy();
}
@@ -320,7 +337,7 @@
mAnimationContext->runRemainingAnimations(info);
GL_CHECKPOINT(MODERATE);
- freePrefetchedLayers(info.observer);
+ freePrefetchedLayers();
GL_CHECKPOINT(MODERATE);
mIsDirty = true;
@@ -504,19 +521,19 @@
}
}
-void CanvasContext::freePrefetchedLayers(TreeObserver* observer) {
+void CanvasContext::freePrefetchedLayers() {
if (mPrefetchedLayers.size()) {
for (auto& node : mPrefetchedLayers) {
ALOGW("Incorrectly called buildLayer on View: %s, destroying layer...",
node->getName());
- node->destroyHardwareResources(observer);
- node->decStrong(observer);
+ node->destroyLayers();
+ node->decStrong(nullptr);
}
mPrefetchedLayers.clear();
}
}
-void CanvasContext::buildLayer(RenderNode* node, TreeObserver* observer) {
+void CanvasContext::buildLayer(RenderNode* node) {
ATRACE_CALL();
if (!mRenderPipeline->isContextReady()) return;
@@ -525,7 +542,6 @@
TreeInfo info(TreeInfo::MODE_FULL, *this);
info.damageAccumulator = &mDamageAccumulator;
- info.observer = observer;
info.layerUpdateQueue = &mLayerUpdateQueue;
info.runAnimations = false;
node->prepareTree(info);
@@ -545,12 +561,12 @@
return mRenderPipeline->copyLayerInto(layer, bitmap);
}
-void CanvasContext::destroyHardwareResources(TreeObserver* observer) {
+void CanvasContext::destroyHardwareResources() {
stopDrawing();
if (mRenderPipeline->isContextReady()) {
- freePrefetchedLayers(observer);
+ freePrefetchedLayers();
for (const sp<RenderNode>& node : mRenderNodes) {
- node->destroyHardwareResources(observer);
+ node->destroyHardwareResources();
}
mRenderPipeline->onDestroyHardwareResources();
}