/* * 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 "renderstate/RenderState.h" #include "Readback.h" #include #include #include 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 >& 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(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; } DeferredLayerUpdater* OpenGLPipeline::createTextureLayer() { mEglManager.initialize(); Layer* layer = new Layer(mRenderThread.renderState(), 0, 0); Caches::getInstance().textureState().activateTexture(0); layer->generateTexture(); return new DeferredLayerUpdater(layer); } 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() { 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 > 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(renderer); } TaskManager* OpenGLPipeline::getTaskManager() { return &Caches::getInstance().tasks; } } /* namespace renderthread */ } /* namespace uirenderer */ } /* namespace android */