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