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