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 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 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 86 void Layer::onGlContextLost() { 87 removeFbo(); 88 deleteTexture(); 89 } 90 91 uint32_t Layer::computeIdealWidth(uint32_t layerWidth) { 92 return uint32_t(ceilf(layerWidth / float(LAYER_SIZE)) * LAYER_SIZE); 93 } 94 95 uint32_t Layer::computeIdealHeight(uint32_t layerHeight) { 96 return uint32_t(ceilf(layerHeight / float(LAYER_SIZE)) * LAYER_SIZE); 97 } 98 99 void Layer::requireRenderer() { 100 if (!renderer) { 101 renderer = new LayerRenderer(renderState, this); 102 renderer->initProperties(); 103 } 104 } 105 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 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 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 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 190 void Layer::setPaint(const SkPaint* paint) { 191 OpenGLRenderer::getAlphaAndModeDirect(paint, &alpha, &mode); 192 setColorFilter((paint) ? paint->getColorFilter() : NULL); 193 } 194 195 void Layer::setColorFilter(SkColorFilter* filter) { 196 SkRefCnt_SafeAssign(colorFilter, filter); 197 } 198 199 void Layer::bindTexture() const { 200 if (texture.id) { 201 caches.bindTexture(renderTarget, texture.id); 202 } 203 } 204 205 void Layer::bindStencilRenderBuffer() const { 206 if (stencil) { 207 stencil->bind(); 208 } 209 } 210 211 void Layer::generateTexture() { 212 if (!texture.id) { 213 glGenTextures(1, &texture.id); 214 } 215 } 216 217 void Layer::deleteTexture() { 218 if (texture.id) { 219 texture.deleteTexture(); 220 texture.id = 0; 221 } 222 } 223 224 void Layer::clearTexture() { 225 caches.unbindTexture(texture.id); 226 texture.id = 0; 227 } 228 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 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 268 void Layer::cancelDefer() { 269 renderNode = NULL; 270 deferredUpdateScheduled = false; 271 if (deferredList) { 272 delete deferredList; 273 deferredList = NULL; 274 } 275 } 276 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 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 316 void Layer::postDecStrong() { 317 renderState.postDecStrong(this); 318 } 319 320 }; // namespace uirenderer 321 }; // namespace android 322