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