Refactor CanvasContext: move OpenGL specific code

Move OpenGL specific code from CanvasContext into a new class
OpenGLPipeline.

Change-Id: I4363053f890701a4235927b59ec588861488ea8f
diff --git a/libs/hwui/renderthread/OpenGLPipeline.cpp b/libs/hwui/renderthread/OpenGLPipeline.cpp
new file mode 100644
index 0000000..3a2b155
--- /dev/null
+++ b/libs/hwui/renderthread/OpenGLPipeline.cpp
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "OpenGLPipeline.h"
+
+#include "DeferredLayerUpdater.h"
+#include "EglManager.h"
+#include "LayerRenderer.h"
+#include "renderstate/RenderState.h"
+#include "Readback.h"
+
+#include <android/native_window.h>
+#include <cutils/properties.h>
+#include <strings.h>
+
+namespace android {
+namespace uirenderer {
+namespace renderthread {
+
+OpenGLPipeline::OpenGLPipeline(RenderThread& thread)
+        :  mEglManager(thread.eglManager()), mRenderThread(thread) {
+}
+
+MakeCurrentResult OpenGLPipeline::makeCurrent() {
+    // TODO: Figure out why this workaround is needed, see b/13913604
+    // In the meantime this matches the behavior of GLRenderer, so it is not a regression
+    EGLint error = 0;
+    bool haveNewSurface = mEglManager.makeCurrent(mEglSurface, &error);
+
+    Caches::getInstance().textureCache.resetMarkInUse(this);
+    if (!haveNewSurface) {
+        return MakeCurrentResult::AlreadyCurrent;
+    }
+    return error ? MakeCurrentResult::Failed : MakeCurrentResult::Succeeded;
+}
+
+Frame OpenGLPipeline::getFrame() {
+    LOG_ALWAYS_FATAL_IF(mEglSurface == EGL_NO_SURFACE,
+                "drawRenderNode called on a context with no surface!");
+    return mEglManager.beginFrame(mEglSurface);
+}
+
+bool OpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
+        const FrameBuilder::LightGeometry& lightGeometry,
+        LayerUpdateQueue* layerUpdateQueue,
+        const Rect& contentDrawBounds, bool opaque,
+        const BakedOpRenderer::LightInfo& lightInfo,
+        const std::vector< sp<RenderNode> >& renderNodes,
+        FrameInfoVisualizer* profiler) {
+
+    mEglManager.damageFrame(frame, dirty);
+
+    bool drew = false;
+
+
+    auto& caches = Caches::getInstance();
+    FrameBuilder frameBuilder(dirty, frame.width(), frame.height(), lightGeometry, caches);
+
+    frameBuilder.deferLayers(*layerUpdateQueue);
+    layerUpdateQueue->clear();
+
+    frameBuilder.deferRenderNodeScene(renderNodes, contentDrawBounds);
+
+    BakedOpRenderer renderer(caches, mRenderThread.renderState(),
+            opaque, lightInfo);
+    frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
+    profiler->draw(&renderer);
+    drew = renderer.didDraw();
+
+    // post frame cleanup
+    caches.clearGarbage();
+    caches.pathCache.trim();
+    caches.tessellationCache.trim();
+
+#if DEBUG_MEMORY_USAGE
+    mCaches.dumpMemoryUsage();
+#else
+    if (CC_UNLIKELY(Properties::debugLevel & kDebugMemory)) {
+        caches.dumpMemoryUsage();
+    }
+#endif
+
+    return drew;
+}
+
+bool OpenGLPipeline::swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
+        FrameInfo* currentFrameInfo, bool* requireSwap) {
+
+    GL_CHECKPOINT(LOW);
+
+    // Even if we decided to cancel the frame, from the perspective of jank
+    // metrics the frame was swapped at this point
+    currentFrameInfo->markSwapBuffers();
+
+    *requireSwap = drew || mEglManager.damageRequiresSwap();
+
+    if (*requireSwap && (CC_UNLIKELY(!mEglManager.swapBuffers(frame, screenDirty)))) {
+        return false;
+    }
+
+    return *requireSwap;
+}
+
+bool OpenGLPipeline::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
+    layer->apply();
+    return Readback::copyTextureLayerInto(mRenderThread, *(layer->backingLayer()), bitmap)
+            == CopyResult::Success;
+}
+
+Layer* OpenGLPipeline::createTextureLayer() {
+    mEglManager.initialize();
+    return LayerRenderer::createTextureLayer(mRenderThread.renderState());
+}
+
+void OpenGLPipeline::onStop() {
+    if (mEglManager.isCurrent(mEglSurface)) {
+        mEglManager.makeCurrent(EGL_NO_SURFACE);
+    }
+}
+
+bool OpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior) {
+
+    if (mEglSurface != EGL_NO_SURFACE) {
+        mEglManager.destroySurface(mEglSurface);
+        mEglSurface = EGL_NO_SURFACE;
+    }
+
+    if (surface) {
+        mEglSurface = mEglManager.createSurface(surface);
+    }
+
+    if (mEglSurface != EGL_NO_SURFACE) {
+        const bool preserveBuffer = (swapBehavior != SwapBehavior::kSwap_discardBuffer);
+        mBufferPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer);
+        return true;
+    }
+
+    return false;
+}
+
+bool OpenGLPipeline::isSurfaceReady() {
+    return CC_UNLIKELY(mEglSurface != EGL_NO_SURFACE);
+}
+
+bool OpenGLPipeline::isContextReady() {
+    return CC_LIKELY(mEglManager.hasEglContext());
+}
+
+void OpenGLPipeline::onDestroyHardwareResources() {
+    Caches& caches = Caches::getInstance();
+    // Make sure to release all the textures we were owning as there won't
+    // be another draw
+    caches.textureCache.resetMarkInUse(this);
+    mRenderThread.renderState().flush(Caches::FlushMode::Layers);
+}
+
+void OpenGLPipeline::renderLayers(const FrameBuilder::LightGeometry& lightGeometry,
+        LayerUpdateQueue* layerUpdateQueue, bool opaque,
+        const BakedOpRenderer::LightInfo& lightInfo) {
+    static const std::vector< sp<RenderNode> > emptyNodeList;
+    auto& caches = Caches::getInstance();
+    FrameBuilder frameBuilder(*layerUpdateQueue, lightGeometry, caches);
+    layerUpdateQueue->clear();
+    BakedOpRenderer renderer(caches, mRenderThread.renderState(),
+            opaque, lightInfo);
+    LOG_ALWAYS_FATAL_IF(renderer.didDraw(), "shouldn't draw in buildlayer case");
+    frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
+}
+
+TaskManager* OpenGLPipeline::getTaskManager() {
+    return &Caches::getInstance().tasks;
+}
+
+} /* namespace renderthread */
+} /* namespace uirenderer */
+} /* namespace android */