Switch DisplayListData to a staging model

 Bug: 13912977

Change-Id: I5b2f664e797be22a58300964f57ceb4fab60528c
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index ce711b6..358e1af 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -73,7 +73,7 @@
             success = LayerRenderer::resizeLayer(mLayer, mWidth, mHeight);
         }
         mLayer->setBlend(mBlend);
-        mDisplayList->updateProperties();
+        mDisplayList->pushStagingChanges();
         mLayer->updateDeferred(mDisplayList.get(),
                 mDirtyRect.left, mDirtyRect.top, mDirtyRect.right, mDirtyRect.bottom);
         mDirtyRect.setEmpty();
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 9dbcd36..f37487f 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1901,7 +1901,6 @@
     // will be performed by the display list itself
     if (displayList && displayList->isRenderable()) {
         // compute 3d ordering
-        displayList->updateProperties();
         displayList->computeOrdering();
         if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
             status = startFrame();
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 5010076..761fb84 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -49,7 +49,12 @@
     fflush(file);
 }
 
-RenderNode::RenderNode() : mDestroyed(false), mNeedsPropertiesSync(false), mDisplayListData(0) {
+RenderNode::RenderNode()
+        : mDestroyed(false)
+        , mNeedsPropertiesSync(false)
+        , mNeedsDisplayListDataSync(false)
+        , mDisplayListData(0)
+        , mStagingDisplayListData(0) {
 }
 
 RenderNode::~RenderNode() {
@@ -57,13 +62,15 @@
 
     mDestroyed = true;
     delete mDisplayListData;
+    delete mStagingDisplayListData;
 }
 
-void RenderNode::setData(DisplayListData* data) {
-    delete mDisplayListData;
-    mDisplayListData = data;
-    if (mDisplayListData) {
-        Caches::getInstance().registerFunctors(mDisplayListData->functorCount);
+void RenderNode::setStagingDisplayList(DisplayListData* data) {
+    mNeedsDisplayListDataSync = true;
+    delete mStagingDisplayListData;
+    mStagingDisplayListData = data;
+    if (mStagingDisplayListData) {
+        Caches::getInstance().registerFunctors(mStagingDisplayListData->functorCount);
     }
 }
 
@@ -86,16 +93,29 @@
     ALOGD("%*sDone (%p, %s)", (level - 1) * 2, "", this, mName.string());
 }
 
-void RenderNode::updateProperties() {
+void RenderNode::pushStagingChanges() {
     if (mNeedsPropertiesSync) {
         mNeedsPropertiesSync = false;
         mProperties = mStagingProperties;
     }
+    if (mNeedsDisplayListDataSync) {
+        mNeedsDisplayListDataSync = false;
+        // Do a push pass on the old tree to handle freeing DisplayListData
+        // that are no longer used
+        pushSubTreeStagingChanges(mDisplayListData);
+        delete mDisplayListData;
+        mDisplayListData = mStagingDisplayListData;
+        mStagingDisplayListData = 0;
+    }
 
-    if (mDisplayListData) {
-        for (size_t i = 0; i < mDisplayListData->children().size(); i++) {
-            RenderNode* childNode = mDisplayListData->children()[i]->mDisplayList;
-            childNode->updateProperties();
+    pushSubTreeStagingChanges(mDisplayListData);
+}
+
+void RenderNode::pushSubTreeStagingChanges(DisplayListData* subtree) {
+    if (subtree) {
+        for (size_t i = 0; i < subtree->children().size(); i++) {
+            RenderNode* childNode = subtree->children()[i]->mDisplayList;
+            childNode->pushStagingChanges();
         }
     }
 }
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index fd0fabc..fcf3b74 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -89,7 +89,7 @@
 
     ANDROID_API static void outputLogBuffer(int fd);
 
-    ANDROID_API void setData(DisplayListData* newData);
+    ANDROID_API void setStagingDisplayList(DisplayListData* newData);
 
     void computeOrdering();
 
@@ -141,7 +141,7 @@
         return properties().getHeight();
     }
 
-    ANDROID_API void updateProperties();
+    ANDROID_API void pushStagingChanges();
 
     // Returns true if this RenderNode or any of its children have functors
     bool hasFunctors();
@@ -203,6 +203,8 @@
         const char* mText;
     };
 
+    static void pushSubTreeStagingChanges(DisplayListData* subtree);
+
     String8 mName;
     bool mDestroyed; // used for debugging crash, TODO: remove once invalid state crash fixed
 
@@ -210,7 +212,9 @@
     RenderProperties mProperties;
     RenderProperties mStagingProperties;
 
+    bool mNeedsDisplayListDataSync;
     DisplayListData* mDisplayListData;
+    DisplayListData* mStagingDisplayListData;
 
     /**
      * Draw time state - these properties are only set and used during rendering
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index c231f6f..ad2e330 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -379,10 +379,6 @@
     mCanvas->setViewport(width, height);
 }
 
-void CanvasContext::setDisplayListData(RenderNode* displayList, DisplayListData* newData) {
-    displayList->setData(newData);
-}
-
 void CanvasContext::processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters) {
     mGlobalContext->makeCurrent(mEglSurface);
     for (size_t i = 0; i < layerUpdaters->size(); i++) {
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 6f1c37f..c878e8f 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -64,7 +64,6 @@
     bool initialize(EGLNativeWindowType window);
     void updateSurface(EGLNativeWindowType window);
     void setup(int width, int height);
-    void setDisplayListData(RenderNode* displayList, DisplayListData* newData);
     void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters);
     void drawDisplayList(RenderNode* displayList, Rect* dirty);
     void destroyCanvas();
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 7b509a2..6e7ec9b 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -30,18 +30,6 @@
 namespace uirenderer {
 namespace renderthread {
 
-SetDisplayListData::SetDisplayListData() : mNewData(0) {}
-
-SetDisplayListData::SetDisplayListData(RenderNode* node, DisplayListData* newData)
-        : mTargetNode(node), mNewData(newData) {
-}
-
-SetDisplayListData::~SetDisplayListData() {}
-
-void SetDisplayListData::apply() const {
-    mTargetNode->setData(mNewData);
-}
-
 DrawFrameTask::DrawFrameTask() : mContext(0), mTaskMode(MODE_INVALID), mRenderNode(0) {
 }
 
@@ -52,13 +40,6 @@
     mContext = context;
 }
 
-void DrawFrameTask::setDisplayListData(RenderNode* renderNode, DisplayListData* newData) {
-    LOG_ALWAYS_FATAL_IF(!mContext, "Lifecycle violation, there's no context to setDisplayListData with!");
-
-    SetDisplayListData setter(renderNode, newData);
-    mDisplayListDataUpdates.push(setter);
-}
-
 void DrawFrameTask::addLayer(DeferredLayerUpdater* layer) {
     LOG_ALWAYS_FATAL_IF(!mContext, "Lifecycle violation, there's no context to addLayer with!");
 
@@ -143,17 +124,11 @@
 void DrawFrameTask::syncFrameState() {
     ATRACE_CALL();
 
-    for (size_t i = 0; i < mDisplayListDataUpdates.size(); i++) {
-        const SetDisplayListData& setter = mDisplayListDataUpdates[i];
-        setter.apply();
-    }
-    mDisplayListDataUpdates.clear();
-
     mContext->processLayerUpdates(&mLayers);
 
     // If we don't have an mRenderNode this is a state flush only
     if (mRenderNode.get()) {
-        mRenderNode->updateProperties();
+        mRenderNode->pushStagingChanges();
     }
 }
 
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index 4e9b244..ddf756b 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -37,18 +37,6 @@
 class CanvasContext;
 class RenderThread;
 
-class SetDisplayListData {
-public:
-    // This ctor exists for Vector's usage
-    SetDisplayListData();
-    SetDisplayListData(RenderNode* node, DisplayListData* newData);
-    ~SetDisplayListData();
-    void apply() const;
-private:
-    sp<RenderNode> mTargetNode;
-    DisplayListData* mNewData;
-};
-
 /*
  * This is a special Super Task. It is re-used multiple times by RenderProxy,
  * and contains state (such as layer updaters & new DisplayListDatas) that is
@@ -62,7 +50,6 @@
 
     void setContext(CanvasContext* context);
 
-    void setDisplayListData(RenderNode* renderNode, DisplayListData* newData);
     void addLayer(DeferredLayerUpdater* layer);
     void removeLayer(DeferredLayerUpdater* layer);
 
@@ -100,7 +87,6 @@
     TaskMode mTaskMode;
     sp<RenderNode> mRenderNode;
     Rect mDirty;
-    Vector<SetDisplayListData> mDisplayListDataUpdates;
 
     /*********************************************
      *  Multi frame data
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index e817e61..d238409 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -124,10 +124,6 @@
     post(task);
 }
 
-void RenderProxy::setDisplayListData(RenderNode* renderNode, DisplayListData* newData) {
-    mDrawFrameTask.setDisplayListData(renderNode, newData);
-}
-
 void RenderProxy::drawDisplayList(RenderNode* displayList,
         int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom) {
     mDrawFrameTask.setRenderNode(displayList);
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index c50da79..8cb414d 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -62,7 +62,6 @@
     ANDROID_API bool initialize(EGLNativeWindowType window);
     ANDROID_API void updateSurface(EGLNativeWindowType window);
     ANDROID_API void setup(int width, int height);
-    ANDROID_API void setDisplayListData(RenderNode* renderNode, DisplayListData* newData);
     ANDROID_API void drawDisplayList(RenderNode* displayList,
             int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);
     ANDROID_API void destroyCanvas();