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