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