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