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