1 /*
2  * Copyright (C) 2012 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 #define LOG_TAG "OpenGLRenderer"
18 
19 #include <utils/Log.h>
20 
21 #include "Caches.h"
22 #include "DeferredDisplayList.h"
23 #include "Layer.h"
24 #include "LayerRenderer.h"
25 #include "OpenGLRenderer.h"
26 #include "RenderNode.h"
27 #include "RenderState.h"
28 #include "utils/TraceUtils.h"
29 
30 #define ATRACE_LAYER_WORK(label) \
31     ATRACE_FORMAT("%s HW Layer DisplayList %s %ux%u", \
32             label, \
33             (renderNode.get() != NULL) ? renderNode->getName() : "", \
34             getWidth(), getHeight())
35 
36 namespace android {
37 namespace uirenderer {
38 
Layer(Type layerType,RenderState & renderState,const uint32_t layerWidth,const uint32_t layerHeight)39 Layer::Layer(Type layerType, RenderState& renderState, const uint32_t layerWidth, const uint32_t layerHeight)
40         : state(kState_Uncached)
41         , caches(Caches::getInstance())
42         , renderState(renderState)
43         , texture(caches)
44         , type(layerType) {
45     // TODO: This is a violation of Android's typical ref counting, but it
46     // preserves the old inc/dec ref locations. This should be changed...
47     incStrong(0);
48     mesh = NULL;
49     meshElementCount = 0;
50     cacheable = true;
51     dirty = false;
52     renderTarget = GL_TEXTURE_2D;
53     texture.width = layerWidth;
54     texture.height = layerHeight;
55     colorFilter = NULL;
56     deferredUpdateScheduled = false;
57     renderer = NULL;
58     renderNode = NULL;
59     fbo = 0;
60     stencil = NULL;
61     debugDrawUpdate = false;
62     hasDrawnSinceUpdate = false;
63     forceFilter = false;
64     deferredList = NULL;
65     convexMask = NULL;
66     rendererLightPosDirty = true;
67     wasBuildLayered = false;
68     renderState.registerLayer(this);
69 }
70 
~Layer()71 Layer::~Layer() {
72     renderState.unregisterLayer(this);
73     SkSafeUnref(colorFilter);
74 
75     if (stencil || fbo || texture.id) {
76         renderState.requireGLContext();
77         removeFbo();
78         deleteTexture();
79     }
80 
81     delete[] mesh;
82     delete deferredList;
83     delete renderer;
84 }
85 
onGlContextLost()86 void Layer::onGlContextLost() {
87     removeFbo();
88     deleteTexture();
89 }
90 
computeIdealWidth(uint32_t layerWidth)91 uint32_t Layer::computeIdealWidth(uint32_t layerWidth) {
92     return uint32_t(ceilf(layerWidth / float(LAYER_SIZE)) * LAYER_SIZE);
93 }
94 
computeIdealHeight(uint32_t layerHeight)95 uint32_t Layer::computeIdealHeight(uint32_t layerHeight) {
96     return uint32_t(ceilf(layerHeight / float(LAYER_SIZE)) * LAYER_SIZE);
97 }
98 
requireRenderer()99 void Layer::requireRenderer() {
100     if (!renderer) {
101         renderer = new LayerRenderer(renderState, this);
102         renderer->initProperties();
103     }
104 }
105 
updateLightPosFromRenderer(const OpenGLRenderer & rootRenderer)106 void Layer::updateLightPosFromRenderer(const OpenGLRenderer& rootRenderer) {
107     if (renderer && rendererLightPosDirty) {
108         // re-init renderer's light position, based upon last cached location in window
109         Vector3 lightPos = rootRenderer.getLightCenter();
110         cachedInvTransformInWindow.mapPoint3d(lightPos);
111         renderer->initLight(lightPos, rootRenderer.getLightRadius(),
112                 rootRenderer.getAmbientShadowAlpha(), rootRenderer.getSpotShadowAlpha());
113         rendererLightPosDirty = false;
114     }
115 }
116 
resize(const uint32_t width,const uint32_t height)117 bool Layer::resize(const uint32_t width, const uint32_t height) {
118     uint32_t desiredWidth = computeIdealWidth(width);
119     uint32_t desiredHeight = computeIdealWidth(height);
120 
121     if (desiredWidth <= getWidth() && desiredHeight <= getHeight()) {
122         return true;
123     }
124 
125     ATRACE_NAME("resizeLayer");
126 
127     const uint32_t maxTextureSize = caches.maxTextureSize;
128     if (desiredWidth > maxTextureSize || desiredHeight > maxTextureSize) {
129         ALOGW("Layer exceeds max. dimensions supported by the GPU (%dx%d, max=%dx%d)",
130                 desiredWidth, desiredHeight, maxTextureSize, maxTextureSize);
131         return false;
132     }
133 
134     uint32_t oldWidth = getWidth();
135     uint32_t oldHeight = getHeight();
136 
137     setSize(desiredWidth, desiredHeight);
138 
139     if (fbo) {
140         caches.activeTexture(0);
141         bindTexture();
142         allocateTexture();
143 
144         if (glGetError() != GL_NO_ERROR) {
145             setSize(oldWidth, oldHeight);
146             return false;
147         }
148     }
149 
150     if (stencil) {
151         stencil->bind();
152         stencil->resize(desiredWidth, desiredHeight);
153 
154         if (glGetError() != GL_NO_ERROR) {
155             setSize(oldWidth, oldHeight);
156             return false;
157         }
158     }
159 
160     return true;
161 }
162 
removeFbo(bool flush)163 void Layer::removeFbo(bool flush) {
164     if (stencil) {
165         GLuint previousFbo = renderState.getFramebuffer();
166         renderState.bindFramebuffer(fbo);
167         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
168         renderState.bindFramebuffer(previousFbo);
169 
170         caches.renderBufferCache.put(stencil);
171         stencil = NULL;
172     }
173 
174     if (fbo) {
175         if (flush) LayerRenderer::flushLayer(renderState, this);
176         // If put fails the cache will delete the FBO
177         caches.fboCache.put(fbo);
178         fbo = 0;
179     }
180 }
181 
updateDeferred(RenderNode * renderNode,int left,int top,int right,int bottom)182 void Layer::updateDeferred(RenderNode* renderNode, int left, int top, int right, int bottom) {
183     requireRenderer();
184     this->renderNode = renderNode;
185     const Rect r(left, top, right, bottom);
186     dirtyRect.unionWith(r);
187     deferredUpdateScheduled = true;
188 }
189 
setPaint(const SkPaint * paint)190 void Layer::setPaint(const SkPaint* paint) {
191     OpenGLRenderer::getAlphaAndModeDirect(paint, &alpha, &mode);
192     setColorFilter((paint) ? paint->getColorFilter() : NULL);
193 }
194 
setColorFilter(SkColorFilter * filter)195 void Layer::setColorFilter(SkColorFilter* filter) {
196     SkRefCnt_SafeAssign(colorFilter, filter);
197 }
198 
bindTexture() const199 void Layer::bindTexture() const {
200     if (texture.id) {
201         caches.bindTexture(renderTarget, texture.id);
202     }
203 }
204 
bindStencilRenderBuffer() const205 void Layer::bindStencilRenderBuffer() const {
206     if (stencil) {
207         stencil->bind();
208     }
209 }
210 
generateTexture()211 void Layer::generateTexture() {
212     if (!texture.id) {
213         glGenTextures(1, &texture.id);
214     }
215 }
216 
deleteTexture()217 void Layer::deleteTexture() {
218     if (texture.id) {
219         texture.deleteTexture();
220         texture.id = 0;
221     }
222 }
223 
clearTexture()224 void Layer::clearTexture() {
225     caches.unbindTexture(texture.id);
226     texture.id = 0;
227 }
228 
allocateTexture()229 void Layer::allocateTexture() {
230 #if DEBUG_LAYERS
231     ALOGD("  Allocate layer: %dx%d", getWidth(), getHeight());
232 #endif
233     if (texture.id) {
234         glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
235         glTexImage2D(renderTarget, 0, GL_RGBA, getWidth(), getHeight(), 0,
236                 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
237     }
238 }
239 
defer(const OpenGLRenderer & rootRenderer)240 void Layer::defer(const OpenGLRenderer& rootRenderer) {
241     ATRACE_LAYER_WORK("Optimize");
242 
243     updateLightPosFromRenderer(rootRenderer);
244     const float width = layer.getWidth();
245     const float height = layer.getHeight();
246 
247     if (dirtyRect.isEmpty() || (dirtyRect.left <= 0 && dirtyRect.top <= 0 &&
248             dirtyRect.right >= width && dirtyRect.bottom >= height)) {
249         dirtyRect.set(0, 0, width, height);
250     }
251 
252     delete deferredList;
253     deferredList = new DeferredDisplayList(dirtyRect);
254 
255     DeferStateStruct deferredState(*deferredList, *renderer,
256             RenderNode::kReplayFlag_ClipChildren);
257 
258     renderer->setViewport(width, height);
259     renderer->setupFrameState(dirtyRect.left, dirtyRect.top,
260             dirtyRect.right, dirtyRect.bottom, !isBlend());
261 
262     renderNode->computeOrdering();
263     renderNode->defer(deferredState, 0);
264 
265     deferredUpdateScheduled = false;
266 }
267 
cancelDefer()268 void Layer::cancelDefer() {
269     renderNode = NULL;
270     deferredUpdateScheduled = false;
271     if (deferredList) {
272         delete deferredList;
273         deferredList = NULL;
274     }
275 }
276 
flush()277 void Layer::flush() {
278     // renderer is checked as layer may be destroyed/put in layer cache with flush scheduled
279     if (deferredList && renderer) {
280         ATRACE_LAYER_WORK("Issue");
281         renderer->startMark((renderNode.get() != NULL) ? renderNode->getName() : "Layer");
282 
283         renderer->setViewport(layer.getWidth(), layer.getHeight());
284         renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom,
285                 !isBlend());
286 
287         deferredList->flush(*renderer, dirtyRect);
288 
289         renderer->finish();
290 
291         dirtyRect.setEmpty();
292         renderNode = NULL;
293 
294         renderer->endMark();
295     }
296 }
297 
render(const OpenGLRenderer & rootRenderer)298 void Layer::render(const OpenGLRenderer& rootRenderer) {
299     ATRACE_LAYER_WORK("Direct-Issue");
300 
301     updateLightPosFromRenderer(rootRenderer);
302     renderer->setViewport(layer.getWidth(), layer.getHeight());
303     renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom,
304             !isBlend());
305 
306     renderer->drawRenderNode(renderNode.get(), dirtyRect, RenderNode::kReplayFlag_ClipChildren);
307 
308     renderer->finish();
309 
310     dirtyRect.setEmpty();
311 
312     deferredUpdateScheduled = false;
313     renderNode = NULL;
314 }
315 
postDecStrong()316 void Layer::postDecStrong() {
317     renderState.postDecStrong(this);
318 }
319 
320 }; // namespace uirenderer
321 }; // namespace android
322