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