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