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