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