OpenGLPipeline.cpp revision 56ad6ec42f814e9e61030ff819cac4e5d31def8b
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 "renderstate/RenderState.h"
22#include "Readback.h"
23
24#include <android/native_window.h>
25#include <cutils/properties.h>
26#include <strings.h>
27
28namespace android {
29namespace uirenderer {
30namespace renderthread {
31
32OpenGLPipeline::OpenGLPipeline(RenderThread& thread)
33        :  mEglManager(thread.eglManager()), mRenderThread(thread) {
34}
35
36MakeCurrentResult OpenGLPipeline::makeCurrent() {
37    // TODO: Figure out why this workaround is needed, see b/13913604
38    // In the meantime this matches the behavior of GLRenderer, so it is not a regression
39    EGLint error = 0;
40    bool haveNewSurface = mEglManager.makeCurrent(mEglSurface, &error);
41
42    Caches::getInstance().textureCache.resetMarkInUse(this);
43    if (!haveNewSurface) {
44        return MakeCurrentResult::AlreadyCurrent;
45    }
46    return error ? MakeCurrentResult::Failed : MakeCurrentResult::Succeeded;
47}
48
49Frame OpenGLPipeline::getFrame() {
50    LOG_ALWAYS_FATAL_IF(mEglSurface == EGL_NO_SURFACE,
51                "drawRenderNode called on a context with no surface!");
52    return mEglManager.beginFrame(mEglSurface);
53}
54
55bool OpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
56        const FrameBuilder::LightGeometry& lightGeometry,
57        LayerUpdateQueue* layerUpdateQueue,
58        const Rect& contentDrawBounds, bool opaque,
59        const BakedOpRenderer::LightInfo& lightInfo,
60        const std::vector< sp<RenderNode> >& renderNodes,
61        FrameInfoVisualizer* profiler) {
62
63    mEglManager.damageFrame(frame, dirty);
64
65    bool drew = false;
66
67
68    auto& caches = Caches::getInstance();
69    FrameBuilder frameBuilder(dirty, frame.width(), frame.height(), lightGeometry, caches);
70
71    frameBuilder.deferLayers(*layerUpdateQueue);
72    layerUpdateQueue->clear();
73
74    frameBuilder.deferRenderNodeScene(renderNodes, contentDrawBounds);
75
76    BakedOpRenderer renderer(caches, mRenderThread.renderState(),
77            opaque, lightInfo);
78    frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
79    profiler->draw(&renderer);
80    drew = renderer.didDraw();
81
82    // post frame cleanup
83    caches.clearGarbage();
84    caches.pathCache.trim();
85    caches.tessellationCache.trim();
86
87#if DEBUG_MEMORY_USAGE
88    mCaches.dumpMemoryUsage();
89#else
90    if (CC_UNLIKELY(Properties::debugLevel & kDebugMemory)) {
91        caches.dumpMemoryUsage();
92    }
93#endif
94
95    return drew;
96}
97
98bool OpenGLPipeline::swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
99        FrameInfo* currentFrameInfo, bool* requireSwap) {
100
101    GL_CHECKPOINT(LOW);
102
103    // Even if we decided to cancel the frame, from the perspective of jank
104    // metrics the frame was swapped at this point
105    currentFrameInfo->markSwapBuffers();
106
107    *requireSwap = drew || mEglManager.damageRequiresSwap();
108
109    if (*requireSwap && (CC_UNLIKELY(!mEglManager.swapBuffers(frame, screenDirty)))) {
110        return false;
111    }
112
113    return *requireSwap;
114}
115
116bool OpenGLPipeline::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
117    layer->apply();
118    return Readback::copyTextureLayerInto(mRenderThread, *(layer->backingLayer()), bitmap)
119            == CopyResult::Success;
120}
121
122DeferredLayerUpdater* OpenGLPipeline::createTextureLayer() {
123    mEglManager.initialize();
124    Layer* layer = new Layer(mRenderThread.renderState(), 0, 0);
125    Caches::getInstance().textureState().activateTexture(0);
126    layer->generateTexture();
127
128    return new DeferredLayerUpdater(layer);
129}
130
131void OpenGLPipeline::onStop() {
132    if (mEglManager.isCurrent(mEglSurface)) {
133        mEglManager.makeCurrent(EGL_NO_SURFACE);
134    }
135}
136
137bool OpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior) {
138
139    if (mEglSurface != EGL_NO_SURFACE) {
140        mEglManager.destroySurface(mEglSurface);
141        mEglSurface = EGL_NO_SURFACE;
142    }
143
144    if (surface) {
145        mEglSurface = mEglManager.createSurface(surface);
146    }
147
148    if (mEglSurface != EGL_NO_SURFACE) {
149        const bool preserveBuffer = (swapBehavior != SwapBehavior::kSwap_discardBuffer);
150        mBufferPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer);
151        return true;
152    }
153
154    return false;
155}
156
157bool OpenGLPipeline::isSurfaceReady() {
158    return CC_UNLIKELY(mEglSurface != EGL_NO_SURFACE);
159}
160
161bool OpenGLPipeline::isContextReady() {
162    return CC_LIKELY(mEglManager.hasEglContext());
163}
164
165void OpenGLPipeline::onDestroyHardwareResources() {
166    Caches& caches = Caches::getInstance();
167    // Make sure to release all the textures we were owning as there won't
168    // be another draw
169    caches.textureCache.resetMarkInUse(this);
170    mRenderThread.renderState().flush(Caches::FlushMode::Layers);
171}
172
173void OpenGLPipeline::renderLayers(const FrameBuilder::LightGeometry& lightGeometry,
174        LayerUpdateQueue* layerUpdateQueue, bool opaque,
175        const BakedOpRenderer::LightInfo& lightInfo) {
176    static const std::vector< sp<RenderNode> > emptyNodeList;
177    auto& caches = Caches::getInstance();
178    FrameBuilder frameBuilder(*layerUpdateQueue, lightGeometry, caches);
179    layerUpdateQueue->clear();
180    BakedOpRenderer renderer(caches, mRenderThread.renderState(),
181            opaque, lightInfo);
182    LOG_ALWAYS_FATAL_IF(renderer.didDraw(), "shouldn't draw in buildlayer case");
183    frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
184}
185
186TaskManager* OpenGLPipeline::getTaskManager() {
187    return &Caches::getInstance().tasks;
188}
189
190} /* namespace renderthread */
191} /* namespace uirenderer */
192} /* namespace android */
193