Clear root level reorder lists to prevent accessing stale DisplayLists
bug:12581401
Adds temporary logging which should log/crash earlier on incorrectly
reordering hierarchies.
Change-Id: Iee00940718c3cc868161e754aff93cd3b2747094
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index a156341..3c8495e 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -261,6 +261,7 @@
mHeight = 0;
mPivotExplicitlySet = false;
mCaching = false;
+ mOrderingId = 0;
}
size_t DisplayList::getSize() {
@@ -501,13 +502,20 @@
*/
void DisplayList::computeOrdering() {
ATRACE_CALL();
- if (mDisplayListData == NULL) return;
+ m3dNodes.clear();
+ mProjectedNodes.clear();
+ mRootDisplayList = this;
+ mOrderingId++;
+ // TODO: create temporary DDLOp and call computeOrderingImpl on top DisplayList so that
+ // transform properties are applied correctly to top level children
+ if (mDisplayListData == NULL) return;
for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) {
DrawDisplayListOp* childOp = mDisplayListData->children[i];
childOp->mDisplayList->computeOrderingImpl(childOp,
&m3dNodes, &mat4::identity(),
- &mProjectedNodes, &mat4::identity());
+ &mProjectedNodes, &mat4::identity(),
+ mRootDisplayList, mOrderingId);
}
}
@@ -516,7 +524,14 @@
Vector<ZDrawDisplayListOpPair>* compositedChildrenOf3dRoot,
const mat4* transformFrom3dRoot,
Vector<DrawDisplayListOp*>* compositedChildrenOfProjectionSurface,
- const mat4* transformFromProjectionSurface) {
+ const mat4* transformFromProjectionSurface,
+ const void* rootDisplayList, const int orderingId) {
+ m3dNodes.clear();
+ mProjectedNodes.clear();
+
+ // Temporary, for logging
+ mRootDisplayList = rootDisplayList;
+ mOrderingId = orderingId;
// TODO: should avoid this calculation in most cases
// TODO: just calculate single matrix, down to all leaf composited elements
@@ -546,7 +561,6 @@
opState->mSkipInOrderDraw = false;
}
- m3dNodes.clear();
if (mIsContainedVolume) {
// create a new 3d space for descendents by collecting them
compositedChildrenOf3dRoot = &m3dNodes;
@@ -556,7 +570,6 @@
transformFrom3dRoot = &localTransformFrom3dRoot;
}
- mProjectedNodes.clear();
if (mDisplayListData != NULL && mDisplayListData->projectionIndex >= 0) {
// create a new projection surface for descendents by collecting them
compositedChildrenOfProjectionSurface = &mProjectedNodes;
@@ -571,7 +584,8 @@
DrawDisplayListOp* childOp = mDisplayListData->children[i];
childOp->mDisplayList->computeOrderingImpl(childOp,
compositedChildrenOf3dRoot, transformFrom3dRoot,
- compositedChildrenOfProjectionSurface, transformFromProjectionSurface);
+ compositedChildrenOfProjectionSurface, transformFromProjectionSurface,
+ rootDisplayList, orderingId);
}
}
}
@@ -585,6 +599,7 @@
}
inline LinearAllocator& allocator() { return *(mDeferStruct.mAllocator); }
+ const DisplayList* getRoot() { return mDeferStruct.mRoot; }
private:
DeferStateStruct& mDeferStruct;
const int mLevel;
@@ -607,6 +622,7 @@
}
inline LinearAllocator& allocator() { return *(mReplayStruct.mAllocator); }
+ const DisplayList* getRoot() { return mReplayStruct.mRoot; }
private:
ReplayStateStruct& mReplayStruct;
const int mLevel;
@@ -643,6 +659,14 @@
const float zValue = m3dNodes[i].key;
DrawDisplayListOp* childOp = m3dNodes[i].value;
+ if (CC_UNLIKELY(handler.getRoot()->mRootDisplayList != childOp->mDisplayList->mRootDisplayList ||
+ handler.getRoot()->mOrderingId != childOp->mDisplayList->mOrderingId)) {
+ ALOGW("Error in 3d order computation: Root %p, order %d, expected %p %d",
+ childOp->mDisplayList->mRootDisplayList, childOp->mDisplayList->mOrderingId,
+ handler.getRoot()->mRootDisplayList, handler.getRoot()->mOrderingId);
+ CRASH();
+ }
+
if (mode == kPositiveZChildren && zValue < 0.0f) continue;
if (mode == kNegativeZChildren && zValue > 0.0f) break;
@@ -704,6 +728,15 @@
ALOGW("Error: %s is drawing after destruction, size %d", getName(), mSize);
CRASH();
}
+
+ if (CC_UNLIKELY(handler.getRoot()->mRootDisplayList != mRootDisplayList ||
+ handler.getRoot()->mOrderingId != mOrderingId)) {
+ ALOGW("Error in order computation: Root %p, order %d, expected %p %d",
+ mRootDisplayList, mOrderingId,
+ handler.getRoot()->mRootDisplayList, handler.getRoot()->mOrderingId);
+ CRASH();
+ }
+
if (mSize == 0 || mAlpha <= 0) {
DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, mName.string());
return;
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index 5399185..8026c4a 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -76,7 +76,7 @@
class PlaybackStateStruct {
protected:
PlaybackStateStruct(OpenGLRenderer& renderer, int replayFlags, LinearAllocator* allocator)
- : mRenderer(renderer), mReplayFlags(replayFlags), mAllocator(allocator){}
+ : mRenderer(renderer), mReplayFlags(replayFlags), mAllocator(allocator), mRoot(NULL) {}
public:
OpenGLRenderer& mRenderer;
@@ -85,6 +85,7 @@
// Allocator with the lifetime of a single frame.
// replay uses an Allocator owned by the struct, while defer shares the DeferredDisplayList's Allocator
LinearAllocator * const mAllocator;
+ const DisplayList* mRoot; // TEMPORARY, for debug logging only
};
class DeferStateStruct : public PlaybackStateStruct {
@@ -195,6 +196,9 @@
}
void setProjectToContainedVolume(bool shouldProject) {
+ if (!mProjectToContainedVolume && shouldProject) {
+ ALOGD("DL %s(%p) marked for projection", getName(), this);
+ }
mProjectToContainedVolume = shouldProject;
}
@@ -260,6 +264,9 @@
void setTranslationZ(float translationZ) {
if (translationZ != mTranslationZ) {
+ if (mTranslationZ == 0.0f) {
+ ALOGD("DL %s(%p) marked for 3d compositing", getName(), this);
+ }
mTranslationZ = translationZ;
onTranslationUpdate();
}
@@ -527,10 +534,11 @@
void applyViewPropertyTransforms(mat4& matrix);
void computeOrderingImpl(DrawDisplayListOp* opState,
- Vector<ZDrawDisplayListOpPair>* compositedChildrenOf3dRoot,
- const mat4* transformFrom3dRoot,
- Vector<DrawDisplayListOp*>* compositedChildrenOfProjectionSurface,
- const mat4* transformFromProjectionSurface);
+ Vector<ZDrawDisplayListOpPair>* compositedChildrenOf3dRoot,
+ const mat4* transformFrom3dRoot,
+ Vector<DrawDisplayListOp*>* compositedChildrenOfProjectionSurface,
+ const mat4* transformFromProjectionSurface,
+ const void* rootDisplayList, const int orderingId);
template <class T>
inline void setViewProperties(OpenGLRenderer& renderer, T& handler, const int level);
@@ -623,6 +631,10 @@
// for projection surfaces, contains a list of all children items
Vector<DrawDisplayListOp*> mProjectedNodes;
+
+ // TEMPORARY, for debug logging only
+ const void* mRootDisplayList;
+ int mOrderingId;
}; // class DisplayList
}; // namespace uirenderer
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 742ffd47..ed571fa 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -199,6 +199,7 @@
DeferStateStruct deferredState(*deferredList, *renderer,
DisplayList::kReplayFlag_ClipChildren);
+ deferredState.mRoot = displayList;
renderer->initViewport(width, height);
renderer->setupFrameState(dirtyRect.left, dirtyRect.top,
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 7ee803f..741e953 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1877,6 +1877,7 @@
if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
status = startFrame();
ReplayStateStruct replayStruct(*this, dirty, replayFlags);
+ replayStruct.mRoot = displayList;
displayList->replay(replayStruct, 0);
return status | replayStruct.mDrawGlStatus;
}
@@ -1884,6 +1885,7 @@
bool avoidOverdraw = !mCaches.debugOverdraw && !mCountOverdraw; // shh, don't tell devs!
DeferredDisplayList deferredList(*currentClipRect(), avoidOverdraw);
DeferStateStruct deferStruct(deferredList, *this, replayFlags);
+ deferStruct.mRoot = displayList;
displayList->defer(deferStruct, 0);
flushLayers();