Merge hasFunctors & pushStaging into prepareTree

 Bug: 13902607
 Fixes synchronous mode for WebView in HardwareLayers

Change-Id: I90de1e26dcfd9b75cc2f03bac72705fc23237b68
diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java
index b589cc2..eba4f7f 100644
--- a/core/java/android/view/GLRenderer.java
+++ b/core/java/android/view/GLRenderer.java
@@ -1317,7 +1317,7 @@
         }
 
         Trace.traceBegin(Trace.TRACE_TAG_VIEW, "drawDisplayList");
-        nPushStagingChanges(displayList.getNativeDisplayList());
+        nPrepareTree(displayList.getNativeDisplayList());
         try {
             status |= canvas.drawDisplayList(displayList, mRedrawClip,
                     RenderNode.FLAG_CLIP_CHILDREN);
@@ -1476,7 +1476,7 @@
 
     static native void nDestroyLayer(long layerPtr);
 
-    private static native void nPushStagingChanges(long displayListPtr);
+    private static native void nPrepareTree(long displayListPtr);
 
     class DrawPerformanceDataProvider extends GraphDataProvider {
         private final int mGraphType;
diff --git a/core/jni/android_view_GLRenderer.cpp b/core/jni/android_view_GLRenderer.cpp
index 8f59e87..6ae6c8f 100644
--- a/core/jni/android_view_GLRenderer.cpp
+++ b/core/jni/android_view_GLRenderer.cpp
@@ -142,11 +142,12 @@
     LayerRenderer::destroyLayer(layer);
 }
 
-static void android_view_GLRenderer_pushStagingChanges(JNIEnv* env, jobject clazz,
+static void android_view_GLRenderer_prepareTree(JNIEnv* env, jobject clazz,
         jlong renderNodePtr) {
     using namespace android::uirenderer;
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
-    renderNode->pushStagingChanges();
+    TreeInfo info = {0};
+    renderNode->prepareTree(info);
 }
 
 static void android_view_GLRenderer_invokeFunctor(JNIEnv* env, jobject clazz,
@@ -187,7 +188,7 @@
 
     { "getSystemTime",         "()J",   (void*) android_view_GLRenderer_getSystemTime },
     { "nDestroyLayer",         "(J)V",  (void*) android_view_GLRenderer_destroyLayer },
-    { "nPushStagingChanges", "(J)V", (void*) android_view_GLRenderer_pushStagingChanges },
+    { "nPrepareTree", "(J)V", (void*) android_view_GLRenderer_prepareTree },
     { "nInvokeFunctor",        "(JZ)V", (void*) android_view_GLRenderer_invokeFunctor },
 #endif
 
diff --git a/core/jni/android_view_HardwareLayer.cpp b/core/jni/android_view_HardwareLayer.cpp
index 4bf5f78..2eb0d78 100644
--- a/core/jni/android_view_HardwareLayer.cpp
+++ b/core/jni/android_view_HardwareLayer.cpp
@@ -127,7 +127,8 @@
 static jboolean android_view_HardwareLayer_flushChanges(JNIEnv* env, jobject clazz,
         jlong layerUpdaterPtr) {
     DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
-    return layer->apply();
+    bool ignoredHasFunctors;
+    return layer->apply(&ignoredHasFunctors);
 }
 
 static jlong android_view_HardwareLayer_getLayer(JNIEnv* env, jobject clazz,
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 358e1af..c64c169 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -62,7 +62,7 @@
     }
 }
 
-bool DeferredLayerUpdater::apply() {
+bool DeferredLayerUpdater::apply(bool* hasFunctors) {
     bool success = true;
     // These properties are applied the same to both layer types
     mLayer->setColorFilter(mColorFilter);
@@ -73,7 +73,11 @@
             success = LayerRenderer::resizeLayer(mLayer, mWidth, mHeight);
         }
         mLayer->setBlend(mBlend);
-        mDisplayList->pushStagingChanges();
+        TreeInfo info = {0};
+        mDisplayList->prepareTree(info);
+        if (info.hasFunctors) {
+            *hasFunctors = true;
+        }
         mLayer->updateDeferred(mDisplayList.get(),
                 mDirtyRect.left, mDirtyRect.top, mDirtyRect.right, mDirtyRect.bottom);
         mDirtyRect.setEmpty();
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index ce08c2d..2cc9229 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -77,7 +77,7 @@
 
     ANDROID_API void setPaint(const SkPaint* paint);
 
-    ANDROID_API bool apply();
+    ANDROID_API bool apply(bool* hasFunctors);
 
     ANDROID_API Layer* backingLayer() {
         return mLayer;
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 761fb84..823ae7b 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -93,7 +93,18 @@
     ALOGD("%*sDone (%p, %s)", (level - 1) * 2, "", this, mName.string());
 }
 
-void RenderNode::pushStagingChanges() {
+void RenderNode::prepareTree(TreeInfo& info) {
+    ATRACE_CALL();
+
+    prepareTreeImpl(info);
+}
+
+void RenderNode::prepareTreeImpl(TreeInfo& info) {
+    pushStagingChanges(info);
+    prepareSubTree(info, mDisplayListData);
+}
+
+void RenderNode::pushStagingChanges(TreeInfo& info) {
     if (mNeedsPropertiesSync) {
         mNeedsPropertiesSync = false;
         mProperties = mStagingProperties;
@@ -102,41 +113,27 @@
         mNeedsDisplayListDataSync = false;
         // Do a push pass on the old tree to handle freeing DisplayListData
         // that are no longer used
-        pushSubTreeStagingChanges(mDisplayListData);
+        TreeInfo oldTreeInfo = {0};
+        prepareSubTree(oldTreeInfo, mDisplayListData);
+        // TODO: The damage for the old tree should be accounted for
         delete mDisplayListData;
         mDisplayListData = mStagingDisplayListData;
         mStagingDisplayListData = 0;
     }
-
-    pushSubTreeStagingChanges(mDisplayListData);
 }
 
-void RenderNode::pushSubTreeStagingChanges(DisplayListData* subtree) {
+void RenderNode::prepareSubTree(TreeInfo& info, DisplayListData* subtree) {
     if (subtree) {
+        if (!info.hasFunctors) {
+            info.hasFunctors = subtree->functorCount;
+        }
         for (size_t i = 0; i < subtree->children().size(); i++) {
             RenderNode* childNode = subtree->children()[i]->mDisplayList;
-            childNode->pushStagingChanges();
+            childNode->prepareTreeImpl(info);
         }
     }
 }
 
-bool RenderNode::hasFunctors() {
-    if (!mDisplayListData) return false;
-
-    if (mDisplayListData->functorCount) {
-        return true;
-    }
-
-    for (size_t i = 0; i < mDisplayListData->children().size(); i++) {
-        RenderNode* childNode = mDisplayListData->children()[i]->mDisplayList;
-        if (childNode->hasFunctors()) {
-            return true;
-        }
-    }
-
-    return false;
-}
-
 /*
  * For property operations, we pass a savecount of 0, since the operations aren't part of the
  * displaylist, and thus don't have to compensate for the record-time/playback-time discrepancy in
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index e5b9d7c..7853701 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -65,6 +65,11 @@
 class RestoreToCountOp;
 class DrawDisplayListOp;
 
+struct TreeInfo {
+    bool hasFunctors;
+    // TODO: Damage calculations? Flag to skip staging pushes for RT animations?
+};
+
 /**
  * Primary class for storing recorded canvas commands, as well as per-View/ViewGroup display properties.
  *
@@ -141,10 +146,7 @@
         return properties().getHeight();
     }
 
-    ANDROID_API void pushStagingChanges();
-
-    // Returns true if this RenderNode or any of its children have functors
-    bool hasFunctors();
+    ANDROID_API void prepareTree(TreeInfo& info);
 
 private:
     typedef key_value_pair_t<float, DrawDisplayListOp*> ZDrawDisplayListOpPair;
@@ -203,7 +205,9 @@
         const char* mText;
     };
 
-    static void pushSubTreeStagingChanges(DisplayListData* subtree);
+    void prepareTreeImpl(TreeInfo& info);
+    void pushStagingChanges(TreeInfo& info);
+    void prepareSubTree(TreeInfo& info, DisplayListData* subtree);
 
     String8 mName;
     bool mDestroyed; // used for debugging crash, TODO: remove once invalid state crash fixed
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 014c7d0..c5122e2 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -385,11 +385,12 @@
     mCanvas->setViewport(width, height);
 }
 
-void CanvasContext::processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters) {
+void CanvasContext::processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters,
+        bool* hasFunctors) {
     mGlobalContext->makeCurrent(mEglSurface);
     for (size_t i = 0; i < layerUpdaters->size(); i++) {
         DeferredLayerUpdater* update = layerUpdaters->itemAt(i);
-        LOG_ALWAYS_FATAL_IF(!update->apply(), "Failed to update layer!");
+        LOG_ALWAYS_FATAL_IF(!update->apply(hasFunctors), "Failed to update layer!");
         if (update->backingLayer()->deferredUpdateScheduled) {
             mCanvas->pushLayerUpdate(update->backingLayer());
         }
@@ -483,7 +484,8 @@
 
 bool CanvasContext::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
     requireGlContext();
-    layer->apply();
+    bool hasFunctors;
+    layer->apply(&hasFunctors);
     return LayerRenderer::copyLayer(layer->backingLayer(), bitmap);
 }
 
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 4d830ba..a24162e 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -65,7 +65,7 @@
     void updateSurface(EGLNativeWindowType window);
     void pauseSurface(EGLNativeWindowType window);
     void setup(int width, int height);
-    void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters);
+    void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters, bool* hasFunctors);
     void drawDisplayList(RenderNode* displayList, Rect* dirty);
     void destroyCanvas();
 
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 6e7ec9b..372d0d0 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -94,7 +94,8 @@
 void DrawFrameTask::run() {
     ATRACE_NAME("DrawFrame");
 
-    syncFrameState();
+    // canUnblockUiThread is temporary until WebView has a solution for syncing frame state
+    bool canUnblockUiThread = syncFrameState();
 
     if (mTaskMode == MODE_STATE_ONLY) {
         unblockUiThread();
@@ -106,9 +107,6 @@
     sp<RenderNode> renderNode = mRenderNode;
     CanvasContext* context = mContext;
 
-    // This is temporary until WebView has a solution for syncing frame state
-    bool canUnblockUiThread = !requiresSynchronousDraw(renderNode.get());
-
     // From this point on anything in "this" is *UNSAFE TO ACCESS*
     if (canUnblockUiThread) {
         unblockUiThread();
@@ -121,15 +119,20 @@
     }
 }
 
-void DrawFrameTask::syncFrameState() {
+bool DrawFrameTask::syncFrameState() {
     ATRACE_CALL();
 
-    mContext->processLayerUpdates(&mLayers);
+    bool hasFunctors = false;
+    mContext->processLayerUpdates(&mLayers, &hasFunctors);
 
     // If we don't have an mRenderNode this is a state flush only
     if (mRenderNode.get()) {
-        mRenderNode->pushStagingChanges();
+        TreeInfo info = {0};
+        mRenderNode->prepareTree(info);
+        hasFunctors |= info.hasFunctors;
     }
+
+    return !hasFunctors;
 }
 
 void DrawFrameTask::unblockUiThread() {
@@ -147,10 +150,6 @@
     context->drawDisplayList(renderNode, dirty);
 }
 
-bool DrawFrameTask::requiresSynchronousDraw(RenderNode* renderNode) {
-    return renderNode->hasFunctors();
-}
-
 } /* namespace renderthread */
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index ddf756b..a512408 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -68,14 +68,10 @@
     };
 
     void postAndWait(RenderThread* renderThread, TaskMode mode);
-    void syncFrameState();
+    bool syncFrameState();
     void unblockUiThread();
     static void drawRenderNode(CanvasContext* context, RenderNode* renderNode, Rect* dirty);
 
-    // This checks to see if there are any drawGlFunctors which would require
-    // a synchronous drawRenderNode()
-    static bool requiresSynchronousDraw(RenderNode* renderNode);
-
     Mutex mLock;
     Condition mSignal;