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