Re-jigger layers

 Bug: 15185239
 Bug: 15238382

 Make DeferredLayerUpdater ref counted so that
 HardwareLayer:finalizer() works non-crashily on
 leaked layers
 Give DeferredLayerUpdater the ability to have a layer destroyer
 set so that leaked layers can still be recycled on the
 RenderThread
 Order layer updates based off of pushLayerUpdate() calls to fix
 issue with nested layers

Change-Id: I4449cee607f7e5126e02fed7464cf48038e3dfdf
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 285c8c3..97e9bf6 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -22,14 +22,19 @@
 namespace android {
 namespace uirenderer {
 
-DeferredLayerUpdater::DeferredLayerUpdater(Layer* layer, OpenGLRenderer* renderer)
+static void defaultLayerDestroyer(Layer* layer) {
+    Caches::getInstance().resourceCache.decrementRefcount(layer);
+}
+
+DeferredLayerUpdater::DeferredLayerUpdater(Layer* layer, LayerDestroyer destroyer)
         : mDisplayList(0)
         , mSurfaceTexture(0)
         , mTransform(0)
         , mNeedsGLContextAttach(false)
         , mUpdateTexImage(false)
         , mLayer(layer)
-        , mCaches(Caches::getInstance()) {
+        , mCaches(Caches::getInstance())
+        , mDestroyer(destroyer) {
     mWidth = mLayer->layer.getWidth();
     mHeight = mLayer->layer.getHeight();
     mBlend = mLayer->isBlend();
@@ -37,14 +42,16 @@
     mAlpha = mLayer->getAlpha();
     mMode = mLayer->getMode();
     mDirtyRect.setEmpty();
+
+    if (!mDestroyer) {
+        mDestroyer = defaultLayerDestroyer;
+    }
 }
 
 DeferredLayerUpdater::~DeferredLayerUpdater() {
     SkSafeUnref(mColorFilter);
     setTransform(0);
-    if (mLayer) {
-        mCaches.resourceCache.decrementRefcount(mLayer);
-    }
+    mDestroyer(mLayer);
 }
 
 void DeferredLayerUpdater::setPaint(const SkPaint* paint) {
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index cc62caa..b7cfe80 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -30,13 +30,15 @@
 namespace android {
 namespace uirenderer {
 
+typedef void (*LayerDestroyer)(Layer* layer);
+
 // Container to hold the properties a layer should be set to at the start
 // of a render pass
-class DeferredLayerUpdater {
+class DeferredLayerUpdater : public VirtualLightRefBase {
 public:
     // Note that DeferredLayerUpdater assumes it is taking ownership of the layer
     // and will not call incrementRef on it as a result.
-    ANDROID_API DeferredLayerUpdater(Layer* layer, OpenGLRenderer* renderer = 0);
+    ANDROID_API DeferredLayerUpdater(Layer* layer, LayerDestroyer = 0);
     ANDROID_API ~DeferredLayerUpdater();
 
     ANDROID_API bool setSize(uint32_t width, uint32_t height) {
@@ -83,12 +85,6 @@
         return mLayer;
     }
 
-    ANDROID_API Layer* detachBackingLayer() {
-        Layer* layer = mLayer;
-        mLayer = 0;
-        return layer;
-    }
-
 private:
     // Generic properties
     uint32_t mWidth;
@@ -111,6 +107,8 @@
     Layer* mLayer;
     Caches& mCaches;
 
+    LayerDestroyer mDestroyer;
+
     void doUpdateTexImage();
 };
 
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index f91e90e..9ebee1d 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -427,27 +427,11 @@
     mHaveNewSurface |= mGlobalContext->makeCurrent(mEglSurface);
 }
 
-void CanvasContext::prepareDraw(const Vector<DeferredLayerUpdater*>* layerUpdaters,
-        TreeInfo& info) {
-    LOG_ALWAYS_FATAL_IF(!mCanvas, "Cannot prepareDraw without a canvas!");
-    makeCurrent();
-
-    processLayerUpdates(layerUpdaters, info);
-    if (info.out.hasAnimations) {
-        // TODO: Uh... crap?
-    }
-    prepareTree(info);
-}
-
-void CanvasContext::processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters,
-        TreeInfo& info) {
-    for (size_t i = 0; i < layerUpdaters->size(); i++) {
-        DeferredLayerUpdater* update = layerUpdaters->itemAt(i);
-        bool success = update->apply(info);
-        LOG_ALWAYS_FATAL_IF(!success, "Failed to update layer!");
-        if (update->backingLayer()->deferredUpdateScheduled) {
-            mCanvas->pushLayerUpdate(update->backingLayer());
-        }
+void CanvasContext::processLayerUpdate(DeferredLayerUpdater* layerUpdater, TreeInfo& info) {
+    bool success = layerUpdater->apply(info);
+    LOG_ALWAYS_FATAL_IF(!success, "Failed to update layer!");
+    if (layerUpdater->backingLayer()->deferredUpdateScheduled) {
+        mCanvas->pushLayerUpdate(layerUpdater->backingLayer());
     }
 }
 
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index a04269b..00c5bf0 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -55,7 +55,8 @@
     void setup(int width, int height, const Vector3& lightCenter, float lightRadius);
     void setOpaque(bool opaque);
     void makeCurrent();
-    void prepareDraw(const Vector<DeferredLayerUpdater*>* layerUpdaters, TreeInfo& info);
+    void processLayerUpdate(DeferredLayerUpdater* layerUpdater, TreeInfo& info);
+    void prepareTree(TreeInfo& info);
     void draw(Rect* dirty);
     void destroyCanvasAndSurface();
 
@@ -83,9 +84,6 @@
 private:
     friend class RegisterFrameCallbackTask;
 
-    void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters, TreeInfo& info);
-    void prepareTree(TreeInfo& info);
-
     void setSurface(ANativeWindow* window);
     void swapBuffers();
     void requireSurface();
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 7ea358f..61d67ca 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -21,6 +21,7 @@
 #include <utils/Log.h>
 #include <utils/Trace.h>
 
+#include "../DeferredLayerUpdater.h"
 #include "../DisplayList.h"
 #include "../RenderNode.h"
 #include "CanvasContext.h"
@@ -47,17 +48,22 @@
     mContext = context;
 }
 
-void DrawFrameTask::addLayer(DeferredLayerUpdater* layer) {
-    LOG_ALWAYS_FATAL_IF(!mContext, "Lifecycle violation, there's no context to addLayer with!");
+void DrawFrameTask::pushLayerUpdate(DeferredLayerUpdater* layer) {
+    LOG_ALWAYS_FATAL_IF(!mContext, "Lifecycle violation, there's no context to pushLayerUpdate with!");
 
-    mLayers.push(layer);
+    for (size_t i = 0; i < mLayers.size(); i++) {
+        if (mLayers[i].get() == layer) {
+            return;
+        }
+    }
+    mLayers.push_back(layer);
 }
 
-void DrawFrameTask::removeLayer(DeferredLayerUpdater* layer) {
+void DrawFrameTask::removeLayerUpdate(DeferredLayerUpdater* layer) {
     for (size_t i = 0; i < mLayers.size(); i++) {
-        if (mLayers[i] == layer) {
-            mLayers.removeAt(i);
-            break;
+        if (mLayers[i].get() == layer) {
+            mLayers.erase(mLayers.begin() + i);
+            return;
         }
     }
 }
@@ -132,7 +138,16 @@
     mContext->makeCurrent();
     Caches::getInstance().textureCache.resetMarkInUse();
     initTreeInfo(info);
-    mContext->prepareDraw(&mLayers, info);
+
+    for (size_t i = 0; i < mLayers.size(); i++) {
+        mContext->processLayerUpdate(mLayers[i].get(), info);
+    }
+    mLayers.clear();
+    if (info.out.hasAnimations) {
+        // TODO: Uh... crap?
+    }
+    mContext->prepareTree(info);
+
     if (info.out.hasAnimations) {
         // TODO: dirty calculations, for now just do a full-screen inval
         mDirty.setEmpty();
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index 30c8880..d4129b6 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -16,10 +16,11 @@
 #ifndef DRAWFRAMETASK_H
 #define DRAWFRAMETASK_H
 
+#include <vector>
+
 #include <utils/Condition.h>
 #include <utils/Mutex.h>
 #include <utils/StrongPointer.h>
-#include <utils/Vector.h>
 
 #include "RenderTask.h"
 
@@ -56,8 +57,8 @@
 
     void setContext(RenderThread* thread, CanvasContext* context);
 
-    void addLayer(DeferredLayerUpdater* layer);
-    void removeLayer(DeferredLayerUpdater* layer);
+    void pushLayerUpdate(DeferredLayerUpdater* layer);
+    void removeLayerUpdate(DeferredLayerUpdater* layer);
 
     void setDirty(int left, int top, int right, int bottom);
     void setDensity(float density) { mDensity = density; }
@@ -83,13 +84,9 @@
     nsecs_t mFrameTimeNanos;
     nsecs_t mRecordDurationNanos;
     float mDensity;
+    std::vector< sp<DeferredLayerUpdater> > mLayers;
 
     int mSyncResult;
-
-    /*********************************************
-     *  Multi frame data
-     *********************************************/
-    Vector<DeferredLayerUpdater*> mLayers;
 };
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 77c0aa7..0901963 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -229,10 +229,21 @@
     postAndWait(task);
 }
 
+CREATE_BRIDGE1(destroyLayer, Layer* layer) {
+    LayerRenderer::destroyLayer(args->layer);
+    return NULL;
+}
+
+static void enqueueDestroyLayer(Layer* layer) {
+    SETUP_TASK(destroyLayer);
+    args->layer = layer;
+    RenderThread::getInstance().queue(task);
+}
+
 CREATE_BRIDGE3(createDisplayListLayer, CanvasContext* context, int width, int height) {
     Layer* layer = args->context->createRenderLayer(args->width, args->height);
     if (!layer) return 0;
-    return new DeferredLayerUpdater(layer);
+    return new DeferredLayerUpdater(layer, enqueueDestroyLayer);
 }
 
 DeferredLayerUpdater* RenderProxy::createDisplayListLayer(int width, int height) {
@@ -242,14 +253,13 @@
     args->context = mContext;
     void* retval = postAndWait(task);
     DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(retval);
-    mDrawFrameTask.addLayer(layer);
     return layer;
 }
 
 CREATE_BRIDGE1(createTextureLayer, CanvasContext* context) {
     Layer* layer = args->context->createTextureLayer();
     if (!layer) return 0;
-    return new DeferredLayerUpdater(layer);
+    return new DeferredLayerUpdater(layer, enqueueDestroyLayer);
 }
 
 DeferredLayerUpdater* RenderProxy::createTextureLayer() {
@@ -257,15 +267,9 @@
     args->context = mContext;
     void* retval = postAndWait(task);
     DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(retval);
-    mDrawFrameTask.addLayer(layer);
     return layer;
 }
 
-CREATE_BRIDGE1(destroyLayer, Layer* layer) {
-    LayerRenderer::destroyLayer(args->layer);
-    return NULL;
-}
-
 CREATE_BRIDGE3(copyLayerInto, CanvasContext* context, DeferredLayerUpdater* layer,
         SkBitmap* bitmap) {
     bool success = args->context->copyLayerInto(args->layer, args->bitmap);
@@ -280,11 +284,12 @@
     return (bool) postAndWait(task);
 }
 
-void RenderProxy::destroyLayer(DeferredLayerUpdater* layer) {
-    mDrawFrameTask.removeLayer(layer);
-    SETUP_TASK(destroyLayer);
-    args->layer = layer->detachBackingLayer();
-    post(task);
+void RenderProxy::pushLayerUpdate(DeferredLayerUpdater* layer) {
+    mDrawFrameTask.pushLayerUpdate(layer);
+}
+
+void RenderProxy::cancelLayerUpdate(DeferredLayerUpdater* layer) {
+    mDrawFrameTask.removeLayerUpdate(layer);
 }
 
 CREATE_BRIDGE2(flushCaches, CanvasContext* context, Caches::FlushMode flushMode) {
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index c8d42ec..944ff9c 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -80,7 +80,8 @@
     ANDROID_API DeferredLayerUpdater* createDisplayListLayer(int width, int height);
     ANDROID_API DeferredLayerUpdater* createTextureLayer();
     ANDROID_API bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap);
-    ANDROID_API void destroyLayer(DeferredLayerUpdater* layer);
+    ANDROID_API void pushLayerUpdate(DeferredLayerUpdater* layer);
+    ANDROID_API void cancelLayerUpdate(DeferredLayerUpdater* layer);
 
     ANDROID_API void flushCaches(Caches::FlushMode flushMode);