Move Layer creation/deletion into the RenderPipeline.

Test: refactoring. existing tests still pass.
Change-Id: I032c33896a0cb74c91e2a913a584373518466b88
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 43471e5..0f2d55b 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -85,6 +85,18 @@
     return nullptr;
 }
 
+void CanvasContext::destroyLayer(RenderNode* node) {
+    auto renderType = Properties::getRenderPipelineType();
+    switch (renderType) {
+        case RenderPipelineType::OpenGL:
+            OpenGLPipeline::destroyLayer(node);
+            break;
+        default:
+            LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType);
+            break;
+    }
+}
+
 CanvasContext::CanvasContext(RenderThread& thread, bool translucent,
         RenderNode* rootRenderNode, IContextFactory* contextFactory,
         std::unique_ptr<IRenderPipeline> renderPipeline)
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 7ebe0ae..652cddd 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -68,6 +68,23 @@
             RenderNode* rootRenderNode, IContextFactory* contextFactory);
     virtual ~CanvasContext();
 
+    /**
+     * Update or create a layer specific for the provided RenderNode. The layer
+     * attached to the node will be specific to the RenderPipeline used by this
+     * context
+     *
+     *  @return true if the layer has been created or updated
+     */
+    bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& dmgAccumulator) {
+        return mRenderPipeline->createOrUpdateLayer(node, dmgAccumulator);
+    }
+
+    /**
+     * Destroy any layers that have been attached to the provided RenderNode removing
+     * any state that may have been set during createOrUpdateLayer().
+     */
+    static void destroyLayer(RenderNode* node);
+
     // Won't take effect until next EGLSurface creation
     void setSwapBehavior(SwapBehavior swapBehavior);
 
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index 3250fed..97cdf7f 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -67,6 +67,8 @@
             LayerUpdateQueue* layerUpdateQueue, bool opaque,
             const BakedOpRenderer::LightInfo& lightInfo) = 0;
     virtual TaskManager* getTaskManager() = 0;
+    virtual bool createOrUpdateLayer(RenderNode* node,
+            const DamageAccumulator& damageAccumulator) = 0;
 
     virtual ~IRenderPipeline() {}
 };
diff --git a/libs/hwui/renderthread/OpenGLPipeline.cpp b/libs/hwui/renderthread/OpenGLPipeline.cpp
index c8971f8..c758f6c 100644
--- a/libs/hwui/renderthread/OpenGLPipeline.cpp
+++ b/libs/hwui/renderthread/OpenGLPipeline.cpp
@@ -183,6 +183,46 @@
     return &Caches::getInstance().tasks;
 }
 
+static bool layerMatchesWH(OffscreenBuffer* layer, int width, int height) {
+    return layer->viewportWidth == (uint32_t)width && layer->viewportHeight == (uint32_t)height;
+}
+
+bool OpenGLPipeline::createOrUpdateLayer(RenderNode* node,
+        const DamageAccumulator& damageAccumulator) {
+    RenderState& renderState = mRenderThread.renderState();
+    OffscreenBufferPool& layerPool = renderState.layerPool();
+    bool transformUpdateNeeded = false;
+    if (node->getLayer() == nullptr) {
+        node->setLayer(layerPool.get(renderState, node->getWidth(), node->getHeight()));
+        transformUpdateNeeded = true;
+    } else if (!layerMatchesWH(node->getLayer(), node->getWidth(), node->getHeight())) {
+        // TODO: remove now irrelevant, currently enqueued damage (respecting damage ordering)
+        // Or, ideally, maintain damage between frames on node/layer so ordering is always correct
+        if (node->properties().fitsOnLayer()) {
+            node->setLayer(layerPool.resize(node->getLayer(), node->getWidth(), node->getHeight()));
+        } else {
+            destroyLayer(node);
+        }
+        transformUpdateNeeded = true;
+    }
+
+    if (transformUpdateNeeded && node->getLayer()) {
+        // update the transform in window of the layer to reset its origin wrt light source position
+        Matrix4 windowTransform;
+        damageAccumulator.computeCurrentTransform(&windowTransform);
+        node->getLayer()->setWindowTransform(windowTransform);
+    }
+
+    return transformUpdateNeeded;
+}
+
+void OpenGLPipeline::destroyLayer(RenderNode* node) {
+    if (OffscreenBuffer* layer = node->getLayer()) {
+        layer->renderState.layerPool().putOrDelete(layer);
+        node->setLayer(nullptr);
+    }
+}
+
 } /* namespace renderthread */
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/renderthread/OpenGLPipeline.h b/libs/hwui/renderthread/OpenGLPipeline.h
index e08fd9b..34d9bc0 100644
--- a/libs/hwui/renderthread/OpenGLPipeline.h
+++ b/libs/hwui/renderthread/OpenGLPipeline.h
@@ -56,6 +56,9 @@
             LayerUpdateQueue* layerUpdateQueue, bool opaque,
             const BakedOpRenderer::LightInfo& lightInfo) override;
     TaskManager* getTaskManager() override;
+    bool createOrUpdateLayer(RenderNode* node,
+            const DamageAccumulator& damageAccumulator) override;
+    static void destroyLayer(RenderNode* node);
 
 private:
     EglManager& mEglManager;