Explicitly destroy Layer in DeferredLayerUpdater on destroyHardwareResources()

Change-Id: I0987104eabda9a2a302b9e765213aad48f93aea4
Test: refactoring CL. Existing tests still pass
bug:33753499
diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp
index 6079d5d..03a397c 100644
--- a/libs/hwui/BakedOpDispatcher.cpp
+++ b/libs/hwui/BakedOpDispatcher.cpp
@@ -18,6 +18,7 @@
 
 #include "BakedOpRenderer.h"
 #include "Caches.h"
+#include "DeferredLayerUpdater.h"
 #include "Glop.h"
 #include "GlopBuilder.h"
 #include "Patch.h"
@@ -762,15 +763,19 @@
 }
 
 void BakedOpDispatcher::onTextureLayerOp(BakedOpRenderer& renderer, const TextureLayerOp& op, const BakedOpState& state) {
-    const bool tryToSnap = !op.layer->getForceFilter();
-    float alpha = (op.layer->getAlpha() / 255.0f) * state.alpha;
+    GlLayer* layer = static_cast<GlLayer*>(op.layerHandle->backingLayer());
+    if (!layer) {
+        return;
+    }
+    const bool tryToSnap = layer->getForceFilter();
+    float alpha = (layer->getAlpha() / 255.0f) * state.alpha;
     Glop glop;
     GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
             .setRoundRectClipState(state.roundRectClipState)
             .setMeshTexturedUvQuad(nullptr, Rect(0, 1, 1, 0)) // TODO: simplify with VBO
-            .setFillTextureLayer(*(op.layer), alpha)
+            .setFillTextureLayer(*(layer), alpha)
             .setTransform(state.computedState.transform, TransformFlags::None)
-            .setModelViewMapUnitToRectOptionalSnap(tryToSnap, Rect(op.layer->getWidth(), op.layer->getHeight()))
+            .setModelViewMapUnitToRectOptionalSnap(tryToSnap, Rect(layer->getWidth(), layer->getHeight()))
             .build();
     renderer.renderGlop(state, glop);
 }
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 0ae50e9..ee77643 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -17,6 +17,7 @@
 
 #include "GlLayer.h"
 #include "VkLayer.h"
+#include "renderstate/RenderState.h"
 #include "renderthread/EglManager.h"
 #include "renderthread/RenderTask.h"
 #include "utils/PaintUtils.h"
@@ -24,25 +25,32 @@
 namespace android {
 namespace uirenderer {
 
-DeferredLayerUpdater::DeferredLayerUpdater(Layer* layer)
-        : mSurfaceTexture(nullptr)
+DeferredLayerUpdater::DeferredLayerUpdater(RenderState& renderState, CreateLayerFn createLayerFn,
+        Layer::Api layerApi)
+        : mRenderState(renderState)
+        , mBlend(false)
+        , mSurfaceTexture(nullptr)
         , mTransform(nullptr)
         , mNeedsGLContextAttach(false)
         , mUpdateTexImage(false)
-        , mLayer(layer) {
-    mWidth = mLayer->getWidth();
-    mHeight = mLayer->getHeight();
-    mBlend = mLayer->isBlend();
-    mColorFilter = SkSafeRef(mLayer->getColorFilter());
-    mAlpha = mLayer->getAlpha();
-    mMode = mLayer->getMode();
+        , mLayer(nullptr)
+        , mLayerApi(layerApi)
+        , mCreateLayerFn(createLayerFn) {
+    renderState.registerDeferredLayerUpdater(this);
 }
 
 DeferredLayerUpdater::~DeferredLayerUpdater() {
     SkSafeUnref(mColorFilter);
     setTransform(nullptr);
-    mLayer->postDecStrong();
-    mLayer = nullptr;
+    mRenderState.unregisterDeferredLayerUpdater(this);
+    destroyLayer();
+}
+
+void DeferredLayerUpdater::destroyLayer() {
+    if (mLayer) {
+        mLayer->postDecStrong();
+        mLayer = nullptr;
+    }
 }
 
 void DeferredLayerUpdater::setPaint(const SkPaint* paint) {
@@ -53,6 +61,10 @@
 }
 
 void DeferredLayerUpdater::apply() {
+    if (!mLayer) {
+        mLayer = mCreateLayerFn(mRenderState, mWidth, mHeight, mColorFilter, mAlpha, mMode, mBlend);
+    }
+
     mLayer->setColorFilter(mColorFilter);
     mLayer->setAlpha(mAlpha, mMode);
 
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index 3814be2..064b724 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -32,13 +32,20 @@
 namespace android {
 namespace uirenderer {
 
+class RenderState;
+
 // Container to hold the properties a layer should be set to at the start
 // of a render pass
 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 explicit DeferredLayerUpdater(Layer* layer);
+    typedef std::function<Layer*(RenderState& renderState, uint32_t layerWidth,
+            uint32_t layerHeight, SkColorFilter* colorFilter, int alpha,
+            SkBlendMode mode, bool blend)> CreateLayerFn;
+    ANDROID_API explicit DeferredLayerUpdater(RenderState& renderState,
+            CreateLayerFn createLayerFn, Layer::Api layerApi);
+
     ANDROID_API ~DeferredLayerUpdater();
 
     ANDROID_API bool setSize(int width, int height) {
@@ -97,20 +104,30 @@
 
     void updateLayer(bool forceFilter, GLenum renderTarget, const float* textureTransform);
 
+    void destroyLayer();
+
+    Layer::Api getBackingLayerApi() {
+        return mLayerApi;
+    }
+
 private:
+    RenderState& mRenderState;
+
     // Generic properties
-    int mWidth;
-    int mHeight;
-    bool mBlend;
-    SkColorFilter* mColorFilter;
-    int mAlpha;
-    SkBlendMode mMode;
+    int mWidth = 0;
+    int mHeight = 0;
+    bool mBlend = false;
+    SkColorFilter* mColorFilter = nullptr;
+    int mAlpha = 255;
+    SkBlendMode mMode = SkBlendMode::kSrcOver;
     sp<GLConsumer> mSurfaceTexture;
     SkMatrix* mTransform;
     bool mNeedsGLContextAttach;
     bool mUpdateTexImage;
 
     Layer* mLayer;
+    Layer::Api mLayerApi;
+    CreateLayerFn mCreateLayerFn;
 
     void doUpdateTexImage();
     void doUpdateVkTexImage();
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
index 1d8b021..35ff635 100644
--- a/libs/hwui/FrameBuilder.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -16,6 +16,7 @@
 
 #include "FrameBuilder.h"
 
+#include "DeferredLayerUpdater.h"
 #include "LayerUpdateQueue.h"
 #include "RenderNode.h"
 #include "VectorDrawable.h"
@@ -784,14 +785,15 @@
 }
 
 void FrameBuilder::deferTextureLayerOp(const TextureLayerOp& op) {
-    if (CC_UNLIKELY(!op.layer->isRenderable())) return;
+    GlLayer* layer = static_cast<GlLayer*>(op.layerHandle->backingLayer());
+    if (CC_UNLIKELY(!layer || !layer->isRenderable())) return;
 
     const TextureLayerOp* textureLayerOp = &op;
     // Now safe to access transform (which was potentially unready at record time)
-    if (!op.layer->getTransform().isIdentity()) {
+    if (!layer->getTransform().isIdentity()) {
         // non-identity transform present, so 'inject it' into op by copying + replacing matrix
         Matrix4 combinedMatrix(op.localMatrix);
-        combinedMatrix.multiply(op.layer->getTransform());
+        combinedMatrix.multiply(layer->getTransform());
         textureLayerOp = mAllocator.create<TextureLayerOp>(op, combinedMatrix);
     }
     BakedOpState* bakedState = tryBakeOpState(*textureLayerOp);
diff --git a/libs/hwui/GlLayer.cpp b/libs/hwui/GlLayer.cpp
index c0ab895..8174bcc 100644
--- a/libs/hwui/GlLayer.cpp
+++ b/libs/hwui/GlLayer.cpp
@@ -32,12 +32,14 @@
 namespace android {
 namespace uirenderer {
 
-GlLayer::GlLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight)
-        : Layer(renderState, Api::OpenGL)
+GlLayer::GlLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
+        SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend)
+        : Layer(renderState, Api::OpenGL, colorFilter, alpha, mode)
         , caches(Caches::getInstance())
         , texture(caches) {
     texture.mWidth = layerWidth;
     texture.mHeight = layerHeight;
+    texture.blend = blend;
 }
 
 GlLayer::~GlLayer() {
diff --git a/libs/hwui/GlLayer.h b/libs/hwui/GlLayer.h
index 54bf5ad..23dfd9d 100644
--- a/libs/hwui/GlLayer.h
+++ b/libs/hwui/GlLayer.h
@@ -31,7 +31,8 @@
  */
 class GlLayer : public Layer {
 public:
-    GlLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight);
+    GlLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
+            SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend);
     virtual ~GlLayer();
 
     uint32_t getWidth() const override {
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 331bb81..b58dfce 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -23,10 +23,14 @@
 namespace android {
 namespace uirenderer {
 
-Layer::Layer(RenderState& renderState, Api api)
+Layer::Layer(RenderState& renderState, Api api, SkColorFilter* colorFilter, int alpha,
+        SkBlendMode mode)
         : GpuMemoryTracker(GpuObjectType::Layer)
         , mRenderState(renderState)
-        , mApi(api) {
+        , mApi(api)
+        , colorFilter(nullptr)
+        , alpha(alpha)
+        , mode(mode) {
     // TODO: This is a violation of Android's typical ref counting, but it
     // preserves the old inc/dec ref locations. This should be changed...
     incStrong(nullptr);
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 3b639ee..e5520ea 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -105,7 +105,8 @@
     void postDecStrong();
 
 protected:
-    Layer(RenderState& renderState, Api api);
+    Layer(RenderState& renderState, Api api, SkColorFilter* colorFilter, int alpha,
+            SkBlendMode mode);
 
     RenderState& mRenderState;
 
@@ -115,7 +116,7 @@
     /**
      * Color filter used to draw this layer. Optional.
      */
-    SkColorFilter* colorFilter = nullptr;
+    SkColorFilter* colorFilter;
 
     /**
      * Indicates raster data backing the layer is scaled, requiring filtration.
@@ -125,12 +126,12 @@
     /**
      * Opacity of the layer.
      */
-    int alpha = 255;
+    int alpha;
 
     /**
      * Blending mode of the layer.
      */
-    SkBlendMode mode = SkBlendMode::kSrcOver;
+    SkBlendMode mode;
 
     /**
      * Optional texture coordinates transform.
diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h
index dea2be6..3b87aef 100644
--- a/libs/hwui/RecordedOp.h
+++ b/libs/hwui/RecordedOp.h
@@ -37,6 +37,8 @@
 struct ClipBase;
 class OffscreenBuffer;
 class RenderNode;
+class DeferredLayerUpdater;
+
 struct Vertex;
 
 namespace VectorDrawable {
@@ -414,18 +416,18 @@
 };
 
 struct TextureLayerOp : RecordedOp {
-    TextureLayerOp(BASE_PARAMS_PAINTLESS, GlLayer* layer)
+    TextureLayerOp(BASE_PARAMS_PAINTLESS, DeferredLayerUpdater* layer)
             : SUPER_PAINTLESS(TextureLayerOp)
-            , layer(layer) {}
+            , layerHandle(layer) {}
 
     // Copy an existing TextureLayerOp, replacing the underlying matrix
     TextureLayerOp(const TextureLayerOp& op, const Matrix4& replacementMatrix)
             : RecordedOp(RecordedOpId::TextureLayerOp, op.unmappedBounds, replacementMatrix,
                     op.localClip, op.paint)
-            , layer(op.layer) {
+            , layerHandle(op.layerHandle) {
 
     }
-    GlLayer* layer;
+    DeferredLayerUpdater* layerHandle;
 };
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index b5e5d68..2e33609 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -606,14 +606,13 @@
     // We ref the DeferredLayerUpdater due to its thread-safe ref-counting semantics.
     mDisplayList->ref(layerHandle);
 
-    LOG_ALWAYS_FATAL_IF(layerHandle->backingLayer()->getApi() != Layer::Api::OpenGL);
+    LOG_ALWAYS_FATAL_IF(layerHandle->getBackingLayerApi() != Layer::Api::OpenGL);
     // Note that the backing layer has *not* yet been updated, so don't trust
     // its width, height, transform, etc...!
     addOp(alloc().create_trivial<TextureLayerOp>(
             Rect(layerHandle->getWidth(), layerHandle->getHeight()),
             *(mState.currentSnapshot()->transform),
-            getRecordedClip(),
-            static_cast<GlLayer*>(layerHandle->backingLayer())));
+            getRecordedClip(), layerHandle));
 }
 
 void RecordingCanvas::callDrawGLFunction(Functor* functor,
diff --git a/libs/hwui/VkLayer.h b/libs/hwui/VkLayer.h
index 39522b3..7e41ad1 100644
--- a/libs/hwui/VkLayer.h
+++ b/libs/hwui/VkLayer.h
@@ -27,8 +27,12 @@
  */
 class VkLayer : public Layer {
 public:
-    VkLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight)
-            : Layer(renderState, Api::Vulkan) {}
+    VkLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
+            SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend)
+            : Layer(renderState, Api::Vulkan, colorFilter, alpha, mode)
+            , mWidth(layerWidth)
+            , mHeight(layerHeight)
+            , mBlend(blend) {}
 
     virtual ~VkLayer() {}
 
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index 65a1dc3..de80ee3 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -135,11 +135,17 @@
     return LayerDrawable::DrawLayer(mRenderThread.getGrContext(), &canvas, layer);
 }
 
+static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
+        SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) {
+    GlLayer* layer = new GlLayer(renderState, layerWidth, layerHeight, colorFilter, alpha,
+            mode, blend);
+    layer->generateTexture();
+    return layer;
+}
+
 DeferredLayerUpdater* SkiaOpenGLPipeline::createTextureLayer() {
     mEglManager.initialize();
-    GlLayer* layer = new GlLayer(mRenderThread.renderState(), 0, 0);
-    layer->generateTexture();
-    return new DeferredLayerUpdater(layer);
+    return new DeferredLayerUpdater(mRenderThread.renderState(), createLayer, Layer::Api::OpenGL);
 }
 
 void SkiaOpenGLPipeline::onStop() {
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index 910c339..c63dce1 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -118,11 +118,15 @@
     return false;
 }
 
+static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
+        SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) {
+    return new VkLayer(renderState, layerWidth, layerHeight, colorFilter, alpha, mode, blend);
+}
+
 DeferredLayerUpdater* SkiaVulkanPipeline::createTextureLayer() {
     mVkManager.initialize();
 
-    VkLayer* layer = new VkLayer(mRenderThread.renderState(), 0, 0);
-    return new DeferredLayerUpdater(layer);
+    return new DeferredLayerUpdater(mRenderThread.renderState(), createLayer, Layer::Api::Vulkan);
 }
 
 void SkiaVulkanPipeline::onStop() {
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
index 17ee390..0d567f7 100644
--- a/libs/hwui/renderstate/RenderState.cpp
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#include "DeferredLayerUpdater.h"
 #include "GlLayer.h"
 #include "VkLayer.h"
 #include <GpuMemoryTracker.h>
@@ -209,6 +210,14 @@
     }
 }
 
+static void destroyLayerInUpdater(DeferredLayerUpdater* layerUpdater) {
+    layerUpdater->destroyLayer();
+}
+
+void RenderState::destroyLayersInUpdater() {
+    std::for_each(mActiveLayerUpdaters.begin(), mActiveLayerUpdaters.end(), destroyLayerInUpdater);
+}
+
 class DecStrongTask : public renderthread::RenderTask {
 public:
     explicit DecStrongTask(VirtualLightRefBase* object) : mObject(object) {}
diff --git a/libs/hwui/renderstate/RenderState.h b/libs/hwui/renderstate/RenderState.h
index d183a15..a44fa9d 100644
--- a/libs/hwui/renderstate/RenderState.h
+++ b/libs/hwui/renderstate/RenderState.h
@@ -42,6 +42,7 @@
 
 class Caches;
 class Layer;
+class DeferredLayerUpdater;
 
 namespace renderthread {
 class CanvasContext;
@@ -90,6 +91,16 @@
         mRegisteredContexts.erase(context);
     }
 
+    void registerDeferredLayerUpdater(DeferredLayerUpdater* layerUpdater) {
+        mActiveLayerUpdaters.insert(layerUpdater);
+    }
+
+    void unregisterDeferredLayerUpdater(DeferredLayerUpdater* layerUpdater) {
+        mActiveLayerUpdaters.erase(layerUpdater);
+    }
+
+    void destroyLayersInUpdater();
+
     // TODO: This system is a little clunky feeling, this could use some
     // more thinking...
     void postDecStrong(VirtualLightRefBase* object);
@@ -126,6 +137,7 @@
     OffscreenBufferPool mLayerPool;
 
     std::set<Layer*> mActiveLayers;
+    std::set<DeferredLayerUpdater*> mActiveLayerUpdaters;
     std::set<renderthread::CanvasContext*> mRegisteredContexts;
 
     GLsizei mViewportWidth;
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index a53e5e0..5a7de1d 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -570,6 +570,7 @@
         }
         mRenderPipeline->onDestroyHardwareResources();
     }
+    mRenderThread.renderState().destroyLayersInUpdater();
 }
 
 void CanvasContext::trimMemory(RenderThread& thread, int level) {
diff --git a/libs/hwui/renderthread/OpenGLPipeline.cpp b/libs/hwui/renderthread/OpenGLPipeline.cpp
index df40a44..8a5d9cc 100644
--- a/libs/hwui/renderthread/OpenGLPipeline.cpp
+++ b/libs/hwui/renderthread/OpenGLPipeline.cpp
@@ -125,13 +125,18 @@
             static_cast<GlLayer&>(*layer->backingLayer()), bitmap);
 }
 
-DeferredLayerUpdater* OpenGLPipeline::createTextureLayer() {
-    mEglManager.initialize();
-    GlLayer* layer = new GlLayer(mRenderThread.renderState(), 0, 0);
+static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
+        SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) {
+    GlLayer* layer = new GlLayer(renderState, layerWidth, layerHeight, colorFilter, alpha,
+            mode, blend);
     Caches::getInstance().textureState().activateTexture(0);
     layer->generateTexture();
+    return layer;
+}
 
-    return new DeferredLayerUpdater(layer);
+DeferredLayerUpdater* OpenGLPipeline::createTextureLayer() {
+    mEglManager.initialize();
+    return new DeferredLayerUpdater(mRenderThread.renderState(), createLayer, Layer::Api::OpenGL);
 }
 
 void OpenGLPipeline::onStop() {
diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp
index 0916d72..3e52c39 100644
--- a/libs/hwui/tests/common/TestUtils.cpp
+++ b/libs/hwui/tests/common/TestUtils.cpp
@@ -60,6 +60,7 @@
         pipeline = new skiapipeline::SkiaVulkanPipeline(renderThread);
     }
     sp<DeferredLayerUpdater> layerUpdater = pipeline->createTextureLayer();
+    layerUpdater->apply();
     delete pipeline;
     return layerUpdater;
 }