diff options
author | Stan Iliev <stani@google.com> | 2016-07-08 21:34:52 -0400 |
---|---|---|
committer | Stan Iliev <stani@google.com> | 2016-07-13 14:14:12 -0400 |
commit | 768e39335b668e8ef25fef30ab42b2d6d29a4735 (patch) | |
tree | 91f0385269fd844a0438159f108c641e34072d2c /libs/hwui/renderthread/OpenGLPipeline.cpp | |
parent | d79f237d63cbf612ad6334c76cf29d88f81c7a8f (diff) |
Refactor CanvasContext: move OpenGL specific code
Move OpenGL specific code from CanvasContext into a new class
OpenGLPipeline.
Change-Id: I4363053f890701a4235927b59ec588861488ea8f
Diffstat (limited to 'libs/hwui/renderthread/OpenGLPipeline.cpp')
-rw-r--r-- | libs/hwui/renderthread/OpenGLPipeline.cpp | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/libs/hwui/renderthread/OpenGLPipeline.cpp b/libs/hwui/renderthread/OpenGLPipeline.cpp new file mode 100644 index 000000000000..3a2b15584d50 --- /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 */ |