OpenGLPipeline.cpp revision daf7229047c44947b9b02ee187fe5b13f30ebd4b
1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "OpenGLPipeline.h" 18 19#include "DeferredLayerUpdater.h" 20#include "EglManager.h" 21#include "ProfileRenderer.h" 22#include "renderstate/RenderState.h" 23#include "Readback.h" 24 25#include <android/native_window.h> 26#include <cutils/properties.h> 27#include <strings.h> 28 29namespace android { 30namespace uirenderer { 31namespace renderthread { 32 33OpenGLPipeline::OpenGLPipeline(RenderThread& thread) 34 : mEglManager(thread.eglManager()), mRenderThread(thread) { 35} 36 37MakeCurrentResult OpenGLPipeline::makeCurrent() { 38 // TODO: Figure out why this workaround is needed, see b/13913604 39 // In the meantime this matches the behavior of GLRenderer, so it is not a regression 40 EGLint error = 0; 41 bool haveNewSurface = mEglManager.makeCurrent(mEglSurface, &error); 42 43 Caches::getInstance().textureCache.resetMarkInUse(this); 44 if (!haveNewSurface) { 45 return MakeCurrentResult::AlreadyCurrent; 46 } 47 return error ? MakeCurrentResult::Failed : MakeCurrentResult::Succeeded; 48} 49 50Frame OpenGLPipeline::getFrame() { 51 LOG_ALWAYS_FATAL_IF(mEglSurface == EGL_NO_SURFACE, 52 "drawRenderNode called on a context with no surface!"); 53 return mEglManager.beginFrame(mEglSurface); 54} 55 56bool OpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty, 57 const FrameBuilder::LightGeometry& lightGeometry, 58 LayerUpdateQueue* layerUpdateQueue, 59 const Rect& contentDrawBounds, bool opaque, 60 const BakedOpRenderer::LightInfo& lightInfo, 61 const std::vector< sp<RenderNode> >& renderNodes, 62 FrameInfoVisualizer* profiler) { 63 64 mEglManager.damageFrame(frame, dirty); 65 66 bool drew = false; 67 68 69 auto& caches = Caches::getInstance(); 70 FrameBuilder frameBuilder(dirty, frame.width(), frame.height(), lightGeometry, caches); 71 72 frameBuilder.deferLayers(*layerUpdateQueue); 73 layerUpdateQueue->clear(); 74 75 frameBuilder.deferRenderNodeScene(renderNodes, contentDrawBounds); 76 77 BakedOpRenderer renderer(caches, mRenderThread.renderState(), 78 opaque, lightInfo); 79 frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer); 80 ProfileRenderer profileRenderer(renderer); 81 profiler->draw(profileRenderer); 82 drew = renderer.didDraw(); 83 84 // post frame cleanup 85 caches.clearGarbage(); 86 caches.pathCache.trim(); 87 caches.tessellationCache.trim(); 88 89#if DEBUG_MEMORY_USAGE 90 mCaches.dumpMemoryUsage(); 91#else 92 if (CC_UNLIKELY(Properties::debugLevel & kDebugMemory)) { 93 caches.dumpMemoryUsage(); 94 } 95#endif 96 97 return drew; 98} 99 100bool OpenGLPipeline::swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty, 101 FrameInfo* currentFrameInfo, bool* requireSwap) { 102 103 GL_CHECKPOINT(LOW); 104 105 // Even if we decided to cancel the frame, from the perspective of jank 106 // metrics the frame was swapped at this point 107 currentFrameInfo->markSwapBuffers(); 108 109 *requireSwap = drew || mEglManager.damageRequiresSwap(); 110 111 if (*requireSwap && (CC_UNLIKELY(!mEglManager.swapBuffers(frame, screenDirty)))) { 112 return false; 113 } 114 115 return *requireSwap; 116} 117 118bool OpenGLPipeline::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) { 119 layer->apply(); 120 return Readback::copyTextureLayerInto(mRenderThread, *(layer->backingLayer()), bitmap) 121 == CopyResult::Success; 122} 123 124DeferredLayerUpdater* OpenGLPipeline::createTextureLayer() { 125 mEglManager.initialize(); 126 Layer* layer = new Layer(mRenderThread.renderState(), 0, 0); 127 Caches::getInstance().textureState().activateTexture(0); 128 layer->generateTexture(); 129 130 return new DeferredLayerUpdater(layer); 131} 132 133void OpenGLPipeline::onStop() { 134 if (mEglManager.isCurrent(mEglSurface)) { 135 mEglManager.makeCurrent(EGL_NO_SURFACE); 136 } 137} 138 139bool OpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior) { 140 141 if (mEglSurface != EGL_NO_SURFACE) { 142 mEglManager.destroySurface(mEglSurface); 143 mEglSurface = EGL_NO_SURFACE; 144 } 145 146 if (surface) { 147 mEglSurface = mEglManager.createSurface(surface); 148 } 149 150 if (mEglSurface != EGL_NO_SURFACE) { 151 const bool preserveBuffer = (swapBehavior != SwapBehavior::kSwap_discardBuffer); 152 mBufferPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer); 153 return true; 154 } 155 156 return false; 157} 158 159bool OpenGLPipeline::isSurfaceReady() { 160 return CC_UNLIKELY(mEglSurface != EGL_NO_SURFACE); 161} 162 163bool OpenGLPipeline::isContextReady() { 164 return CC_LIKELY(mEglManager.hasEglContext()); 165} 166 167void OpenGLPipeline::onDestroyHardwareResources() { 168 Caches& caches = Caches::getInstance(); 169 // Make sure to release all the textures we were owning as there won't 170 // be another draw 171 caches.textureCache.resetMarkInUse(this); 172 mRenderThread.renderState().flush(Caches::FlushMode::Layers); 173} 174 175void OpenGLPipeline::renderLayers(const FrameBuilder::LightGeometry& lightGeometry, 176 LayerUpdateQueue* layerUpdateQueue, bool opaque, 177 const BakedOpRenderer::LightInfo& lightInfo) { 178 static const std::vector< sp<RenderNode> > emptyNodeList; 179 auto& caches = Caches::getInstance(); 180 FrameBuilder frameBuilder(*layerUpdateQueue, lightGeometry, caches); 181 layerUpdateQueue->clear(); 182 BakedOpRenderer renderer(caches, mRenderThread.renderState(), 183 opaque, lightInfo); 184 LOG_ALWAYS_FATAL_IF(renderer.didDraw(), "shouldn't draw in buildlayer case"); 185 frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer); 186} 187 188TaskManager* OpenGLPipeline::getTaskManager() { 189 return &Caches::getInstance().tasks; 190} 191 192static bool layerMatchesWH(OffscreenBuffer* layer, int width, int height) { 193 return layer->viewportWidth == (uint32_t)width && layer->viewportHeight == (uint32_t)height; 194} 195 196bool OpenGLPipeline::createOrUpdateLayer(RenderNode* node, 197 const DamageAccumulator& damageAccumulator) { 198 RenderState& renderState = mRenderThread.renderState(); 199 OffscreenBufferPool& layerPool = renderState.layerPool(); 200 bool transformUpdateNeeded = false; 201 if (node->getLayer() == nullptr) { 202 node->setLayer(layerPool.get(renderState, node->getWidth(), node->getHeight())); 203 transformUpdateNeeded = true; 204 } else if (!layerMatchesWH(node->getLayer(), node->getWidth(), node->getHeight())) { 205 // TODO: remove now irrelevant, currently enqueued damage (respecting damage ordering) 206 // Or, ideally, maintain damage between frames on node/layer so ordering is always correct 207 if (node->properties().fitsOnLayer()) { 208 node->setLayer(layerPool.resize(node->getLayer(), node->getWidth(), node->getHeight())); 209 } else { 210 destroyLayer(node); 211 } 212 transformUpdateNeeded = true; 213 } 214 215 if (transformUpdateNeeded && node->getLayer()) { 216 // update the transform in window of the layer to reset its origin wrt light source position 217 Matrix4 windowTransform; 218 damageAccumulator.computeCurrentTransform(&windowTransform); 219 node->getLayer()->setWindowTransform(windowTransform); 220 } 221 222 return transformUpdateNeeded; 223} 224 225void OpenGLPipeline::destroyLayer(RenderNode* node) { 226 if (OffscreenBuffer* layer = node->getLayer()) { 227 layer->renderState.layerPool().putOrDelete(layer); 228 node->setLayer(nullptr); 229 } 230} 231 232void OpenGLPipeline::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) { 233 if (Caches::hasInstance() && thread.eglManager().hasEglContext()) { 234 ATRACE_NAME("Bitmap#prepareToDraw task"); 235 Caches::getInstance().textureCache.prefetch(bitmap); 236 } 237} 238 239void OpenGLPipeline::invokeFunctor(const RenderThread& thread, Functor* functor) { 240 DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext; 241 if (thread.eglManager().hasEglContext()) { 242 mode = DrawGlInfo::kModeProcess; 243 } 244 thread.renderState().invokeFunctor(functor, mode, nullptr); 245} 246 247} /* namespace renderthread */ 248} /* namespace uirenderer */ 249} /* namespace android */ 250