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