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