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 <cutils/properties.h>
28 #include <strings.h>
29 
30 namespace android {
31 namespace uirenderer {
32 namespace renderthread {
33 
OpenGLPipeline(RenderThread & thread)34 OpenGLPipeline::OpenGLPipeline(RenderThread& thread)
35         :  mEglManager(thread.eglManager())
36         , mRenderThread(thread) {
37 }
38 
makeCurrent()39 MakeCurrentResult 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 
getFrame()52 Frame 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 
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<RenderNode>> & renderNodes,FrameInfoVisualizer * profiler)58 bool 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 
swapBuffers(const Frame & frame,bool drew,const SkRect & screenDirty,FrameInfo * currentFrameInfo,bool * requireSwap)102 bool 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 
copyLayerInto(DeferredLayerUpdater * layer,SkBitmap * bitmap)120 bool OpenGLPipeline::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
121     ATRACE_CALL();
122     // acquire most recent buffer for drawing
123     layer->updateTexImage();
124     layer->apply();
125     return OpenGLReadbackImpl::copyLayerInto(mRenderThread,
126             static_cast<GlLayer&>(*layer->backingLayer()), bitmap);
127 }
128 
createLayer(RenderState & renderState,uint32_t layerWidth,uint32_t layerHeight,SkColorFilter * colorFilter,int alpha,SkBlendMode mode,bool blend)129 static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
130         SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) {
131     GlLayer* layer = new GlLayer(renderState, layerWidth, layerHeight, colorFilter, alpha,
132             mode, blend);
133     Caches::getInstance().textureState().activateTexture(0);
134     layer->generateTexture();
135     return layer;
136 }
137 
createTextureLayer()138 DeferredLayerUpdater* OpenGLPipeline::createTextureLayer() {
139     mEglManager.initialize();
140     return new DeferredLayerUpdater(mRenderThread.renderState(), createLayer, Layer::Api::OpenGL);
141 }
142 
onStop()143 void OpenGLPipeline::onStop() {
144     if (mEglManager.isCurrent(mEglSurface)) {
145         mEglManager.makeCurrent(EGL_NO_SURFACE);
146     }
147 }
148 
setSurface(Surface * surface,SwapBehavior swapBehavior)149 bool OpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior) {
150 
151     if (mEglSurface != EGL_NO_SURFACE) {
152         mEglManager.destroySurface(mEglSurface);
153         mEglSurface = EGL_NO_SURFACE;
154     }
155 
156     if (surface) {
157         mEglSurface = mEglManager.createSurface(surface);
158     }
159 
160     if (mEglSurface != EGL_NO_SURFACE) {
161         const bool preserveBuffer = (swapBehavior != SwapBehavior::kSwap_discardBuffer);
162         mBufferPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer);
163         return true;
164     }
165 
166     return false;
167 }
168 
isSurfaceReady()169 bool OpenGLPipeline::isSurfaceReady() {
170     return CC_UNLIKELY(mEglSurface != EGL_NO_SURFACE);
171 }
172 
isContextReady()173 bool OpenGLPipeline::isContextReady() {
174     return CC_LIKELY(mEglManager.hasEglContext());
175 }
176 
onDestroyHardwareResources()177 void OpenGLPipeline::onDestroyHardwareResources() {
178     Caches& caches = Caches::getInstance();
179     // Make sure to release all the textures we were owning as there won't
180     // be another draw
181     caches.textureCache.resetMarkInUse(this);
182     mRenderThread.renderState().flush(Caches::FlushMode::Layers);
183 }
184 
renderLayers(const FrameBuilder::LightGeometry & lightGeometry,LayerUpdateQueue * layerUpdateQueue,bool opaque,const BakedOpRenderer::LightInfo & lightInfo)185 void OpenGLPipeline::renderLayers(const FrameBuilder::LightGeometry& lightGeometry,
186         LayerUpdateQueue* layerUpdateQueue, bool opaque,
187         const BakedOpRenderer::LightInfo& lightInfo) {
188     static const std::vector< sp<RenderNode> > emptyNodeList;
189     auto& caches = Caches::getInstance();
190     FrameBuilder frameBuilder(*layerUpdateQueue, lightGeometry, caches);
191     layerUpdateQueue->clear();
192     BakedOpRenderer renderer(caches, mRenderThread.renderState(),
193             opaque, lightInfo);
194     LOG_ALWAYS_FATAL_IF(renderer.didDraw(), "shouldn't draw in buildlayer case");
195     frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
196 }
197 
getTaskManager()198 TaskManager* OpenGLPipeline::getTaskManager() {
199     return &Caches::getInstance().tasks;
200 }
201 
layerMatchesWH(OffscreenBuffer * layer,int width,int height)202 static bool layerMatchesWH(OffscreenBuffer* layer, int width, int height) {
203     return layer->viewportWidth == (uint32_t)width && layer->viewportHeight == (uint32_t)height;
204 }
205 
createOrUpdateLayer(RenderNode * node,const DamageAccumulator & damageAccumulator)206 bool OpenGLPipeline::createOrUpdateLayer(RenderNode* node,
207         const DamageAccumulator& damageAccumulator) {
208     RenderState& renderState = mRenderThread.renderState();
209     OffscreenBufferPool& layerPool = renderState.layerPool();
210     bool transformUpdateNeeded = false;
211     if (node->getLayer() == nullptr) {
212         node->setLayer(layerPool.get(renderState, node->getWidth(), node->getHeight()));
213         transformUpdateNeeded = true;
214     } else if (!layerMatchesWH(node->getLayer(), node->getWidth(), node->getHeight())) {
215         // TODO: remove now irrelevant, currently enqueued damage (respecting damage ordering)
216         // Or, ideally, maintain damage between frames on node/layer so ordering is always correct
217         if (node->properties().fitsOnLayer()) {
218             node->setLayer(layerPool.resize(node->getLayer(), node->getWidth(), node->getHeight()));
219         } else {
220             destroyLayer(node);
221         }
222         transformUpdateNeeded = true;
223     }
224 
225     if (transformUpdateNeeded && node->getLayer()) {
226         // update the transform in window of the layer to reset its origin wrt light source position
227         Matrix4 windowTransform;
228         damageAccumulator.computeCurrentTransform(&windowTransform);
229         node->getLayer()->setWindowTransform(windowTransform);
230     }
231 
232     return transformUpdateNeeded;
233 }
234 
pinImages(LsaVector<sk_sp<Bitmap>> & images)235 bool OpenGLPipeline::pinImages(LsaVector<sk_sp<Bitmap>>& images) {
236     TextureCache& cache = Caches::getInstance().textureCache;
237     bool prefetchSucceeded = true;
238     for (auto& bitmapResource : images) {
239         prefetchSucceeded &= cache.prefetchAndMarkInUse(this, bitmapResource.get());
240     }
241     return prefetchSucceeded;
242 }
243 
unpinImages()244 void OpenGLPipeline::unpinImages() {
245     Caches::getInstance().textureCache.resetMarkInUse(this);
246 }
247 
destroyLayer(RenderNode * node)248 void OpenGLPipeline::destroyLayer(RenderNode* node) {
249     if (OffscreenBuffer* layer = node->getLayer()) {
250         layer->renderState.layerPool().putOrDelete(layer);
251         node->setLayer(nullptr);
252     }
253 }
254 
prepareToDraw(const RenderThread & thread,Bitmap * bitmap)255 void OpenGLPipeline::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) {
256     if (Caches::hasInstance() && thread.eglManager().hasEglContext()) {
257         ATRACE_NAME("Bitmap#prepareToDraw task");
258         Caches::getInstance().textureCache.prefetch(bitmap);
259     }
260 }
261 
invokeFunctor(const RenderThread & thread,Functor * functor)262 void OpenGLPipeline::invokeFunctor(const RenderThread& thread, Functor* functor) {
263     DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext;
264     if (thread.eglManager().hasEglContext()) {
265         mode = DrawGlInfo::kModeProcess;
266     }
267     thread.renderState().invokeFunctor(functor, mode, nullptr);
268 }
269 
270 } /* namespace renderthread */
271 } /* namespace uirenderer */
272 } /* namespace android */
273