TextureCache.cpp revision fb8b763f762ae21923c58d64caa729b012f40e05
1/* 2 * Copyright (C) 2010 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 <GLES2/gl2.h> 20 21#include "TextureCache.h" 22#include "Properties.h" 23 24namespace android { 25namespace uirenderer { 26 27/////////////////////////////////////////////////////////////////////////////// 28// Constructors/destructor 29/////////////////////////////////////////////////////////////////////////////// 30 31TextureCache::TextureCache(): 32 mCache(GenerationCache<SkBitmap*, Texture*>::kUnlimitedCapacity), 33 mSize(0), mMaxSize(MB(DEFAULT_TEXTURE_CACHE_SIZE)) { 34 char property[PROPERTY_VALUE_MAX]; 35 if (property_get(PROPERTY_TEXTURE_CACHE_SIZE, property, NULL) > 0) { 36 LOGD(" Setting texture cache size to %sMB", property); 37 setMaxSize(MB(atof(property))); 38 } else { 39 LOGD(" Using default texture cache size of %.2fMB", DEFAULT_TEXTURE_CACHE_SIZE); 40 } 41 42 init(); 43} 44 45TextureCache::TextureCache(uint32_t maxByteSize): 46 mCache(GenerationCache<SkBitmap*, Texture*>::kUnlimitedCapacity), 47 mSize(0), mMaxSize(maxByteSize) { 48 init(); 49} 50 51TextureCache::~TextureCache() { 52 mCache.clear(); 53} 54 55void TextureCache::init() { 56 mCache.setOnEntryRemovedListener(this); 57 58 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); 59 LOGD(" Maximum texture dimension is %d pixels", mMaxTextureSize); 60} 61 62/////////////////////////////////////////////////////////////////////////////// 63// Size management 64/////////////////////////////////////////////////////////////////////////////// 65 66uint32_t TextureCache::getSize() { 67 return mSize; 68} 69 70uint32_t TextureCache::getMaxSize() { 71 return mMaxSize; 72} 73 74void TextureCache::setMaxSize(uint32_t maxSize) { 75 mMaxSize = maxSize; 76 while (mSize > mMaxSize) { 77 mCache.removeOldest(); 78 } 79} 80 81/////////////////////////////////////////////////////////////////////////////// 82// Callbacks 83/////////////////////////////////////////////////////////////////////////////// 84 85void TextureCache::operator()(SkBitmap*& bitmap, Texture*& texture) { 86 if (bitmap) { 87 const uint32_t size = bitmap->rowBytes() * bitmap->height(); 88 mSize -= size; 89 } 90 91 if (texture) { 92 glDeleteTextures(1, &texture->id); 93 delete texture; 94 } 95} 96 97/////////////////////////////////////////////////////////////////////////////// 98// Caching 99/////////////////////////////////////////////////////////////////////////////// 100 101Texture* TextureCache::get(SkBitmap* bitmap) { 102 Texture* texture = mCache.get(bitmap); 103 if (!texture) { 104 if (bitmap->width() > mMaxTextureSize || bitmap->height() > mMaxTextureSize) { 105 LOGW("Bitmap too large to be uploaded into a texture"); 106 return NULL; 107 } 108 109 const uint32_t size = bitmap->rowBytes() * bitmap->height(); 110 // Don't even try to cache a bitmap that's bigger than the cache 111 if (size < mMaxSize) { 112 while (mSize + size > mMaxSize) { 113 mCache.removeOldest(); 114 } 115 } 116 117 texture = new Texture; 118 generateTexture(bitmap, texture, false); 119 120 if (size < mMaxSize) { 121 mSize += size; 122 mCache.put(bitmap, texture); 123 } else { 124 texture->cleanup = true; 125 } 126 } else if (bitmap->getGenerationID() != texture->generation) { 127 generateTexture(bitmap, texture, true); 128 } 129 130 return texture; 131} 132 133void TextureCache::remove(SkBitmap* bitmap) { 134 mCache.remove(bitmap); 135} 136 137void TextureCache::clear() { 138 mCache.clear(); 139} 140 141void TextureCache::generateTexture(SkBitmap* bitmap, Texture* texture, bool regenerate) { 142 SkAutoLockPixels alp(*bitmap); 143 if (!bitmap->readyToDraw()) { 144 LOGE("Cannot generate texture from bitmap"); 145 return; 146 } 147 148 if (!regenerate) { 149 texture->generation = bitmap->getGenerationID(); 150 texture->width = bitmap->width(); 151 texture->height = bitmap->height(); 152 153 glGenTextures(1, &texture->id); 154 } 155 156 glBindTexture(GL_TEXTURE_2D, texture->id); 157 glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel()); 158 159 switch (bitmap->getConfig()) { 160 case SkBitmap::kA8_Config: 161 texture->blend = true; 162 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, bitmap->rowBytesAsPixels(), texture->height, 0, 163 GL_ALPHA, GL_UNSIGNED_BYTE, bitmap->getPixels()); 164 break; 165 case SkBitmap::kRGB_565_Config: 166 texture->blend = false; 167 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, bitmap->rowBytesAsPixels(), texture->height, 0, 168 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, bitmap->getPixels()); 169 break; 170 case SkBitmap::kARGB_8888_Config: 171 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap->rowBytesAsPixels(), texture->height, 0, 172 GL_RGBA, GL_UNSIGNED_BYTE, bitmap->getPixels()); 173 // Do this after calling getPixels() to make sure Skia's deferred 174 // decoding happened 175 texture->blend = !bitmap->isOpaque(); 176 break; 177 default: 178 break; 179 } 180 181 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 182 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 183 184 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 185 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 186} 187 188}; // namespace uirenderer 189}; // namespace android 190