LayerCache.cpp revision 5c88fc744db977ef26887df9605beaa409394806
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 23a1d3c91afbd52c7e8b01f4a9060c5459f02ae7a5Romain Guy#include "Caches.h" 24c9855a53edfac818dc68714557185977556f849dRomain Guy#include "Debug.h" 25dda570201ac851dd85af3861f7e575721d3345daRomain Guy#include "LayerCache.h" 26fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy#include "Properties.h" 27dda570201ac851dd85af3861f7e575721d3345daRomain Guy 28dda570201ac851dd85af3861f7e575721d3345daRomain Guynamespace android { 29dda570201ac851dd85af3861f7e575721d3345daRomain Guynamespace uirenderer { 30dda570201ac851dd85af3861f7e575721d3345daRomain Guy 31dda570201ac851dd85af3861f7e575721d3345daRomain Guy/////////////////////////////////////////////////////////////////////////////// 32dda570201ac851dd85af3861f7e575721d3345daRomain Guy// Constructors/destructor 33dda570201ac851dd85af3861f7e575721d3345daRomain Guy/////////////////////////////////////////////////////////////////////////////// 34dda570201ac851dd85af3861f7e575721d3345daRomain Guy 358550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain GuyLayerCache::LayerCache(): 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) { 38c9855a53edfac818dc68714557185977556f849dRomain Guy INIT_LOGD(" Setting layer cache size to %sMB", property); 39fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy setMaxSize(MB(atof(property))); 40fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy } else { 41c9855a53edfac818dc68714557185977556f849dRomain Guy INIT_LOGD(" Using default layer cache size of %.2fMB", DEFAULT_LAYER_CACHE_SIZE); 42fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy } 43fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy} 44fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy 45dda570201ac851dd85af3861f7e575721d3345daRomain GuyLayerCache::~LayerCache() { 465f0c6a483900f3989f4d2a8f913cf5b6a9777d03Romain Guy clear(); 47dda570201ac851dd85af3861f7e575721d3345daRomain Guy} 48dda570201ac851dd85af3861f7e575721d3345daRomain Guy 49dda570201ac851dd85af3861f7e575721d3345daRomain Guy/////////////////////////////////////////////////////////////////////////////// 50dda570201ac851dd85af3861f7e575721d3345daRomain Guy// Size management 51dda570201ac851dd85af3861f7e575721d3345daRomain Guy/////////////////////////////////////////////////////////////////////////////// 52dda570201ac851dd85af3861f7e575721d3345daRomain Guy 53dda570201ac851dd85af3861f7e575721d3345daRomain Guyuint32_t LayerCache::getSize() { 54dda570201ac851dd85af3861f7e575721d3345daRomain Guy return mSize; 55dda570201ac851dd85af3861f7e575721d3345daRomain Guy} 56dda570201ac851dd85af3861f7e575721d3345daRomain Guy 57dda570201ac851dd85af3861f7e575721d3345daRomain Guyuint32_t LayerCache::getMaxSize() { 58dda570201ac851dd85af3861f7e575721d3345daRomain Guy return mMaxSize; 59dda570201ac851dd85af3861f7e575721d3345daRomain Guy} 60dda570201ac851dd85af3861f7e575721d3345daRomain Guy 61dda570201ac851dd85af3861f7e575721d3345daRomain Guyvoid LayerCache::setMaxSize(uint32_t maxSize) { 628550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy clear(); 63dda570201ac851dd85af3861f7e575721d3345daRomain Guy mMaxSize = maxSize; 64dda570201ac851dd85af3861f7e575721d3345daRomain Guy} 65dda570201ac851dd85af3861f7e575721d3345daRomain Guy 66dda570201ac851dd85af3861f7e575721d3345daRomain Guy/////////////////////////////////////////////////////////////////////////////// 67dda570201ac851dd85af3861f7e575721d3345daRomain Guy// Caching 68dda570201ac851dd85af3861f7e575721d3345daRomain Guy/////////////////////////////////////////////////////////////////////////////// 69dda570201ac851dd85af3861f7e575721d3345daRomain Guy 70dda570201ac851dd85af3861f7e575721d3345daRomain Guyvoid LayerCache::deleteLayer(Layer* layer) { 71dda570201ac851dd85af3861f7e575721d3345daRomain Guy if (layer) { 725c88fc744db977ef26887df9605beaa409394806Romain Guy GLuint fbo = layer->getFbo(); 735c88fc744db977ef26887df9605beaa409394806Romain Guy LAYER_LOGD("Destroying layer %dx%d, fbo %d", layer->getWidth(), layer->getHeight(), fbo); 745c88fc744db977ef26887df9605beaa409394806Romain Guy 759ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy mSize -= layer->getWidth() * layer->getHeight() * 4; 765c88fc744db977ef26887df9605beaa409394806Romain Guy 775c88fc744db977ef26887df9605beaa409394806Romain Guy if (fbo) Caches::getInstance().fboCache.put(fbo); 789ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy layer->deleteTexture(); 795c88fc744db977ef26887df9605beaa409394806Romain Guy 80dda570201ac851dd85af3861f7e575721d3345daRomain Guy delete layer; 81dda570201ac851dd85af3861f7e575721d3345daRomain Guy } 82dda570201ac851dd85af3861f7e575721d3345daRomain Guy} 83dda570201ac851dd85af3861f7e575721d3345daRomain Guy 84dda570201ac851dd85af3861f7e575721d3345daRomain Guyvoid LayerCache::clear() { 858550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy size_t count = mCache.size(); 868550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy for (size_t i = 0; i < count; i++) { 878550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy deleteLayer(mCache.itemAt(i).mLayer); 888550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy } 89dda570201ac851dd85af3861f7e575721d3345daRomain Guy mCache.clear(); 90dda570201ac851dd85af3861f7e575721d3345daRomain Guy} 91dda570201ac851dd85af3861f7e575721d3345daRomain Guy 928550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain GuyLayer* LayerCache::get(const uint32_t width, const uint32_t height) { 938550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy Layer* layer = NULL; 948550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy 958550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy LayerEntry entry(width, height); 968550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy ssize_t index = mCache.indexOf(entry); 97f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy 988550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy if (index >= 0) { 998550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy entry = mCache.itemAt(index); 1008550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy mCache.removeAt(index); 1018550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy 1028550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy layer = entry.mLayer; 1039ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy mSize -= layer->getWidth() * layer->getHeight() * 4; 1048550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy 1059ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy LAYER_LOGD("Reusing layer %dx%d", layer->getWidth(), layer->getHeight()); 106f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy } else { 1078550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy LAYER_LOGD("Creating new layer %dx%d", entry.mWidth, entry.mHeight); 108f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy 1098550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy layer = new Layer(entry.mWidth, entry.mHeight); 1109ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy layer->setBlend(true); 1119ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy layer->setEmpty(true); 1129ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy layer->setFbo(0); 1139ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy 1149ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy layer->generateTexture(); 1159ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy layer->bindTexture(); 11639d252a6632d057d5077f7eaf1b8ed7a142f3397Romain Guy layer->setFilter(GL_NEAREST); 11739d252a6632d057d5077f7eaf1b8ed7a142f3397Romain Guy layer->setWrap(GL_CLAMP_TO_EDGE, false); 1180bb5667b4ef91fefd0500fae0186789d15d54e0eRomain Guy glPixelStorei(GL_UNPACK_ALIGNMENT, 4); 1190bb5667b4ef91fefd0500fae0186789d15d54e0eRomain Guy 120eb99356a0548684a501766e6a524529ab93304c8Romain Guy#if DEBUG_LAYERS 121eea60692b060737faeaa02bb30f5b79e2202b482Romain Guy dump(); 122eb99356a0548684a501766e6a524529ab93304c8Romain Guy#endif 123dda570201ac851dd85af3861f7e575721d3345daRomain Guy } 124f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy 125dda570201ac851dd85af3861f7e575721d3345daRomain Guy return layer; 126dda570201ac851dd85af3861f7e575721d3345daRomain Guy} 127dda570201ac851dd85af3861f7e575721d3345daRomain Guy 128eea60692b060737faeaa02bb30f5b79e2202b482Romain Guyvoid LayerCache::dump() { 129eea60692b060737faeaa02bb30f5b79e2202b482Romain Guy size_t size = mCache.size(); 130eea60692b060737faeaa02bb30f5b79e2202b482Romain Guy for (size_t i = 0; i < size; i++) { 131eea60692b060737faeaa02bb30f5b79e2202b482Romain Guy const LayerEntry& entry = mCache.itemAt(i); 132eea60692b060737faeaa02bb30f5b79e2202b482Romain Guy LAYER_LOGD(" Layer size %dx%d", entry.mWidth, entry.mHeight); 133eea60692b060737faeaa02bb30f5b79e2202b482Romain Guy } 134eea60692b060737faeaa02bb30f5b79e2202b482Romain Guy} 135eea60692b060737faeaa02bb30f5b79e2202b482Romain Guy 13609b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guybool LayerCache::resize(Layer* layer, const uint32_t width, const uint32_t height) { 13709b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy // TODO: We should be smarter and see if we have a texture of the appropriate 13809b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy // size already in the cache, and reuse it instead of creating a new one 13909b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy 14009b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy LayerEntry entry(width, height); 1419ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy if (entry.mWidth <= layer->getWidth() && entry.mHeight <= layer->getHeight()) { 14209b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy return true; 14309b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy } 14409b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy 1459ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy uint32_t oldWidth = layer->getWidth(); 1469ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy uint32_t oldHeight = layer->getHeight(); 14709b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy 148a1d3c91afbd52c7e8b01f4a9060c5459f02ae7a5Romain Guy Caches::getInstance().activeTexture(0); 1499ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy layer->bindTexture(); 1509ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy layer->setSize(entry.mWidth, entry.mHeight); 1519ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy layer->allocateTexture(GL_RGBA, GL_UNSIGNED_BYTE); 15209b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy 15309b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy if (glGetError() != GL_NO_ERROR) { 1549ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy layer->setSize(oldWidth, oldHeight); 15509b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy return false; 15609b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy } 15709b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy 15809b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy return true; 15909b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy} 16009b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy 1618550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guybool LayerCache::put(Layer* layer) { 1629ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy if (!layer->isCacheable()) return false; 163aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy 1649ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy const uint32_t size = layer->getWidth() * layer->getHeight() * 4; 165dda570201ac851dd85af3861f7e575721d3345daRomain Guy // Don't even try to cache a layer that's bigger than the cache 166dda570201ac851dd85af3861f7e575721d3345daRomain Guy if (size < mMaxSize) { 1678550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy // TODO: Use an LRU 168dda570201ac851dd85af3861f7e575721d3345daRomain Guy while (mSize + size > mMaxSize) { 169e91080581f467d55913a8c5ab53dedc2dab2e5b6Romain Guy size_t position = 0; 17028d8ff6dbcc1b137131c70b72b4dbd211db7fbd9Romain Guy#if LAYER_REMOVE_BIGGEST_FIRST 171e91080581f467d55913a8c5ab53dedc2dab2e5b6Romain Guy position = mCache.size() - 1; 172e91080581f467d55913a8c5ab53dedc2dab2e5b6Romain Guy#endif 173e91080581f467d55913a8c5ab53dedc2dab2e5b6Romain Guy Layer* victim = mCache.itemAt(position).mLayer; 174e91080581f467d55913a8c5ab53dedc2dab2e5b6Romain Guy deleteLayer(victim); 175e91080581f467d55913a8c5ab53dedc2dab2e5b6Romain Guy mCache.removeAt(position); 1768550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy 177e91080581f467d55913a8c5ab53dedc2dab2e5b6Romain Guy LAYER_LOGD(" Deleting layer %.2fx%.2f", victim->layer.getWidth(), 178e91080581f467d55913a8c5ab53dedc2dab2e5b6Romain Guy victim->layer.getHeight()); 179dda570201ac851dd85af3861f7e575721d3345daRomain Guy } 180dda570201ac851dd85af3861f7e575721d3345daRomain Guy 1815c88fc744db977ef26887df9605beaa409394806Romain Guy layer->deferredUpdateScheduled = false; 1825c88fc744db977ef26887df9605beaa409394806Romain Guy layer->renderer = NULL; 1835c88fc744db977ef26887df9605beaa409394806Romain Guy layer->displayList = NULL; 1845c88fc744db977ef26887df9605beaa409394806Romain Guy 1858550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy LayerEntry entry(layer); 1868550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy 1878550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy mCache.add(entry); 188dda570201ac851dd85af3861f7e575721d3345daRomain Guy mSize += size; 189dda570201ac851dd85af3861f7e575721d3345daRomain Guy 190dda570201ac851dd85af3861f7e575721d3345daRomain Guy return true; 191dda570201ac851dd85af3861f7e575721d3345daRomain Guy } 192dda570201ac851dd85af3861f7e575721d3345daRomain Guy return false; 193dda570201ac851dd85af3861f7e575721d3345daRomain Guy} 194dda570201ac851dd85af3861f7e575721d3345daRomain Guy 195dda570201ac851dd85af3861f7e575721d3345daRomain Guy}; // namespace uirenderer 196dda570201ac851dd85af3861f7e575721d3345daRomain Guy}; // namespace android 197