LayerCache.cpp revision fb8b763f762ae21923c58d64caa729b012f40e05
1dda570201ac851dd85af3861f7e575721d3345daRomain Guy/* 2dda570201ac851dd85af3861f7e575721d3345daRomain Guy * Copyright (C) 2010 The Android Open Source Project 3dda570201ac851dd85af3861f7e575721d3345daRomain Guy * 4dda570201ac851dd85af3861f7e575721d3345daRomain Guy * Licensed under the Apache License, Version 2.0 (the "License"); 5dda570201ac851dd85af3861f7e575721d3345daRomain Guy * you may not use this file except in compliance with the License. 6dda570201ac851dd85af3861f7e575721d3345daRomain Guy * You may obtain a copy of the License at 7dda570201ac851dd85af3861f7e575721d3345daRomain Guy * 8dda570201ac851dd85af3861f7e575721d3345daRomain Guy * http://www.apache.org/licenses/LICENSE-2.0 9dda570201ac851dd85af3861f7e575721d3345daRomain Guy * 10dda570201ac851dd85af3861f7e575721d3345daRomain Guy * Unless required by applicable law or agreed to in writing, software 11dda570201ac851dd85af3861f7e575721d3345daRomain Guy * distributed under the License is distributed on an "AS IS" BASIS, 12dda570201ac851dd85af3861f7e575721d3345daRomain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13dda570201ac851dd85af3861f7e575721d3345daRomain Guy * See the License for the specific language governing permissions and 14dda570201ac851dd85af3861f7e575721d3345daRomain Guy * limitations under the License. 15dda570201ac851dd85af3861f7e575721d3345daRomain Guy */ 16dda570201ac851dd85af3861f7e575721d3345daRomain Guy 17dda570201ac851dd85af3861f7e575721d3345daRomain Guy#define LOG_TAG "OpenGLRenderer" 18dda570201ac851dd85af3861f7e575721d3345daRomain Guy 19dda570201ac851dd85af3861f7e575721d3345daRomain Guy#include <GLES2/gl2.h> 20dda570201ac851dd85af3861f7e575721d3345daRomain Guy 21f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy#include <utils/Log.h> 22f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy 23dda570201ac851dd85af3861f7e575721d3345daRomain Guy#include "LayerCache.h" 24fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy#include "Properties.h" 25dda570201ac851dd85af3861f7e575721d3345daRomain Guy 26dda570201ac851dd85af3861f7e575721d3345daRomain Guynamespace android { 27dda570201ac851dd85af3861f7e575721d3345daRomain Guynamespace uirenderer { 28dda570201ac851dd85af3861f7e575721d3345daRomain Guy 29dda570201ac851dd85af3861f7e575721d3345daRomain Guy/////////////////////////////////////////////////////////////////////////////// 30dda570201ac851dd85af3861f7e575721d3345daRomain Guy// Constructors/destructor 31dda570201ac851dd85af3861f7e575721d3345daRomain Guy/////////////////////////////////////////////////////////////////////////////// 32dda570201ac851dd85af3861f7e575721d3345daRomain Guy 33fb8b763f762ae21923c58d64caa729b012f40e05Romain GuyLayerCache::LayerCache(): 34fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy mCache(GenerationCache<LayerSize, Layer*>::kUnlimitedCapacity), 35fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy mIdGenerator(1), mSize(0), mMaxSize(MB(DEFAULT_LAYER_CACHE_SIZE)) { 36fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy char property[PROPERTY_VALUE_MAX]; 37fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy if (property_get(PROPERTY_LAYER_CACHE_SIZE, property, NULL) > 0) { 38fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy LOGD(" Setting layer cache size to %sMB", property); 39fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy setMaxSize(MB(atof(property))); 40fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy } else { 41fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy LOGD(" Using default layer cache size of %.2fMB", DEFAULT_LAYER_CACHE_SIZE); 42fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy } 43fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy} 44fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy 45dda570201ac851dd85af3861f7e575721d3345daRomain GuyLayerCache::LayerCache(uint32_t maxByteSize): 466c81893c626499e58c8eeb20d6c35ec4e1ce808bRomain Guy mCache(GenerationCache<LayerSize, Layer*>::kUnlimitedCapacity), 476c81893c626499e58c8eeb20d6c35ec4e1ce808bRomain Guy mIdGenerator(1), mSize(0), mMaxSize(maxByteSize) { 48dda570201ac851dd85af3861f7e575721d3345daRomain Guy} 49dda570201ac851dd85af3861f7e575721d3345daRomain Guy 50dda570201ac851dd85af3861f7e575721d3345daRomain GuyLayerCache::~LayerCache() { 515f0c6a483900f3989f4d2a8f913cf5b6a9777d03Romain Guy clear(); 52dda570201ac851dd85af3861f7e575721d3345daRomain Guy} 53dda570201ac851dd85af3861f7e575721d3345daRomain Guy 54dda570201ac851dd85af3861f7e575721d3345daRomain Guy/////////////////////////////////////////////////////////////////////////////// 55dda570201ac851dd85af3861f7e575721d3345daRomain Guy// Size management 56dda570201ac851dd85af3861f7e575721d3345daRomain Guy/////////////////////////////////////////////////////////////////////////////// 57dda570201ac851dd85af3861f7e575721d3345daRomain Guy 58dda570201ac851dd85af3861f7e575721d3345daRomain Guyuint32_t LayerCache::getSize() { 59dda570201ac851dd85af3861f7e575721d3345daRomain Guy return mSize; 60dda570201ac851dd85af3861f7e575721d3345daRomain Guy} 61dda570201ac851dd85af3861f7e575721d3345daRomain Guy 62dda570201ac851dd85af3861f7e575721d3345daRomain Guyuint32_t LayerCache::getMaxSize() { 63dda570201ac851dd85af3861f7e575721d3345daRomain Guy return mMaxSize; 64dda570201ac851dd85af3861f7e575721d3345daRomain Guy} 65dda570201ac851dd85af3861f7e575721d3345daRomain Guy 66dda570201ac851dd85af3861f7e575721d3345daRomain Guyvoid LayerCache::setMaxSize(uint32_t maxSize) { 67dda570201ac851dd85af3861f7e575721d3345daRomain Guy mMaxSize = maxSize; 68dda570201ac851dd85af3861f7e575721d3345daRomain Guy while (mSize > mMaxSize) { 69dda570201ac851dd85af3861f7e575721d3345daRomain Guy Layer* oldest = mCache.removeOldest(); 70dda570201ac851dd85af3861f7e575721d3345daRomain Guy deleteLayer(oldest); 71dda570201ac851dd85af3861f7e575721d3345daRomain Guy } 72dda570201ac851dd85af3861f7e575721d3345daRomain Guy} 73dda570201ac851dd85af3861f7e575721d3345daRomain Guy 74dda570201ac851dd85af3861f7e575721d3345daRomain Guy/////////////////////////////////////////////////////////////////////////////// 75dda570201ac851dd85af3861f7e575721d3345daRomain Guy// Callbacks 76dda570201ac851dd85af3861f7e575721d3345daRomain Guy/////////////////////////////////////////////////////////////////////////////// 77dda570201ac851dd85af3861f7e575721d3345daRomain Guy 78dda570201ac851dd85af3861f7e575721d3345daRomain Guyvoid LayerCache::operator()(LayerSize& size, Layer*& layer) { 79dda570201ac851dd85af3861f7e575721d3345daRomain Guy deleteLayer(layer); 80dda570201ac851dd85af3861f7e575721d3345daRomain Guy} 81dda570201ac851dd85af3861f7e575721d3345daRomain Guy 82dda570201ac851dd85af3861f7e575721d3345daRomain Guy/////////////////////////////////////////////////////////////////////////////// 83dda570201ac851dd85af3861f7e575721d3345daRomain Guy// Caching 84dda570201ac851dd85af3861f7e575721d3345daRomain Guy/////////////////////////////////////////////////////////////////////////////// 85dda570201ac851dd85af3861f7e575721d3345daRomain Guy 86dda570201ac851dd85af3861f7e575721d3345daRomain Guyvoid LayerCache::deleteLayer(Layer* layer) { 87dda570201ac851dd85af3861f7e575721d3345daRomain Guy if (layer) { 88dda570201ac851dd85af3861f7e575721d3345daRomain Guy mSize -= layer->layer.getWidth() * layer->layer.getHeight() * 4; 89dda570201ac851dd85af3861f7e575721d3345daRomain Guy 90dda570201ac851dd85af3861f7e575721d3345daRomain Guy glDeleteFramebuffers(1, &layer->fbo); 91dda570201ac851dd85af3861f7e575721d3345daRomain Guy glDeleteTextures(1, &layer->texture); 92dda570201ac851dd85af3861f7e575721d3345daRomain Guy delete layer; 93dda570201ac851dd85af3861f7e575721d3345daRomain Guy } 94dda570201ac851dd85af3861f7e575721d3345daRomain Guy} 95dda570201ac851dd85af3861f7e575721d3345daRomain Guy 96dda570201ac851dd85af3861f7e575721d3345daRomain Guyvoid LayerCache::clear() { 97dda570201ac851dd85af3861f7e575721d3345daRomain Guy mCache.setOnEntryRemovedListener(this); 98dda570201ac851dd85af3861f7e575721d3345daRomain Guy mCache.clear(); 99dda570201ac851dd85af3861f7e575721d3345daRomain Guy mCache.setOnEntryRemovedListener(NULL); 100dda570201ac851dd85af3861f7e575721d3345daRomain Guy} 101dda570201ac851dd85af3861f7e575721d3345daRomain Guy 102f18fd99b5c182329cd8936a9611f0103d8ece44aRomain GuyLayer* LayerCache::get(LayerSize& size, GLuint previousFbo) { 103dda570201ac851dd85af3861f7e575721d3345daRomain Guy Layer* layer = mCache.remove(size); 104dda570201ac851dd85af3861f7e575721d3345daRomain Guy if (layer) { 105f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy LAYER_LOGD("Reusing layer"); 106f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy 107dda570201ac851dd85af3861f7e575721d3345daRomain Guy mSize -= layer->layer.getWidth() * layer->layer.getHeight() * 4; 108f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy } else { 109f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy LAYER_LOGD("Creating new layer"); 110f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy 111f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy layer = new Layer; 112f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy layer->blend = true; 113f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy 114f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy // Generate the FBO and attach the texture 115f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy glGenFramebuffers(1, &layer->fbo); 116f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo); 117f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy 118f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy // Generate the texture in which the FBO will draw 119f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy glGenTextures(1, &layer->texture); 120f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy glBindTexture(GL_TEXTURE_2D, layer->texture); 121f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy 122f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy // The FBO will not be scaled, so we can use lower quality filtering 123f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 124f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 125f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy 126f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 127f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 128f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy 129f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width, size.height, 0, 130f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy GL_RGBA, GL_UNSIGNED_BYTE, NULL); 131f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy 132f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy // Bind texture to FBO 133f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 134f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy layer->texture, 0); 135f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy 136f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); 137f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy if (status != GL_FRAMEBUFFER_COMPLETE) { 138f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy LOGE("Framebuffer incomplete (GL error code 0x%x)", status); 139f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy 140f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy glBindFramebuffer(GL_FRAMEBUFFER, previousFbo); 141f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy 142f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy glDeleteFramebuffers(1, &layer->fbo); 143f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy glDeleteTextures(1, &layer->texture); 144f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy delete layer; 145f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy 146f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy return NULL; 147f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy } 148dda570201ac851dd85af3861f7e575721d3345daRomain Guy } 149f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy 150dda570201ac851dd85af3861f7e575721d3345daRomain Guy return layer; 151dda570201ac851dd85af3861f7e575721d3345daRomain Guy} 152dda570201ac851dd85af3861f7e575721d3345daRomain Guy 153dda570201ac851dd85af3861f7e575721d3345daRomain Guybool LayerCache::put(LayerSize& layerSize, Layer* layer) { 154dda570201ac851dd85af3861f7e575721d3345daRomain Guy const uint32_t size = layerSize.width * layerSize.height * 4; 155dda570201ac851dd85af3861f7e575721d3345daRomain Guy // Don't even try to cache a layer that's bigger than the cache 156dda570201ac851dd85af3861f7e575721d3345daRomain Guy if (size < mMaxSize) { 157dda570201ac851dd85af3861f7e575721d3345daRomain Guy while (mSize + size > mMaxSize) { 158dda570201ac851dd85af3861f7e575721d3345daRomain Guy Layer* oldest = mCache.removeOldest(); 159dda570201ac851dd85af3861f7e575721d3345daRomain Guy deleteLayer(oldest); 160dda570201ac851dd85af3861f7e575721d3345daRomain Guy } 161dda570201ac851dd85af3861f7e575721d3345daRomain Guy 1626c81893c626499e58c8eeb20d6c35ec4e1ce808bRomain Guy layerSize.id = mIdGenerator++; 163dda570201ac851dd85af3861f7e575721d3345daRomain Guy mCache.put(layerSize, layer); 164dda570201ac851dd85af3861f7e575721d3345daRomain Guy mSize += size; 165dda570201ac851dd85af3861f7e575721d3345daRomain Guy 166dda570201ac851dd85af3861f7e575721d3345daRomain Guy return true; 167dda570201ac851dd85af3861f7e575721d3345daRomain Guy } 168dda570201ac851dd85af3861f7e575721d3345daRomain Guy return false; 169dda570201ac851dd85af3861f7e575721d3345daRomain Guy} 170dda570201ac851dd85af3861f7e575721d3345daRomain Guy 171dda570201ac851dd85af3861f7e575721d3345daRomain Guy}; // namespace uirenderer 172dda570201ac851dd85af3861f7e575721d3345daRomain Guy}; // namespace android 173