ResourceCache.cpp revision 71d08a07189c2b433080203895d9d5e936b16b9e
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 <SkPixelRef.h> 20#include "ResourceCache.h" 21#include "Caches.h" 22 23namespace android { 24 25#ifdef USE_OPENGL_RENDERER 26using namespace uirenderer; 27ANDROID_SINGLETON_STATIC_INSTANCE(ResourceCache); 28#endif 29 30namespace uirenderer { 31 32/////////////////////////////////////////////////////////////////////////////// 33// Resource cache 34/////////////////////////////////////////////////////////////////////////////// 35 36void ResourceCache::logCache() { 37 ALOGD("ResourceCache: cacheReport:"); 38 for (size_t i = 0; i < mCache->size(); ++i) { 39 ResourceReference* ref = mCache->valueAt(i); 40 ALOGD(" ResourceCache: mCache(%zu): resource, ref = 0x%p, 0x%p", 41 i, mCache->keyAt(i), mCache->valueAt(i)); 42 ALOGD(" ResourceCache: mCache(%zu): refCount, recycled, destroyed, type = %d, %d, %d, %d", 43 i, ref->refCount, ref->recycled, ref->destroyed, ref->resourceType); 44 } 45} 46 47ResourceCache::ResourceCache() { 48 Mutex::Autolock _l(mLock); 49 mCache = new KeyedVector<const void*, ResourceReference*>(); 50} 51 52ResourceCache::~ResourceCache() { 53 Mutex::Autolock _l(mLock); 54 delete mCache; 55} 56 57void ResourceCache::lock() { 58 mLock.lock(); 59} 60 61void ResourceCache::unlock() { 62 mLock.unlock(); 63} 64 65void ResourceCache::incrementRefcount(void* resource, ResourceType resourceType) { 66 Mutex::Autolock _l(mLock); 67 incrementRefcountLocked(resource, resourceType); 68} 69 70void ResourceCache::incrementRefcount(const SkBitmap* bitmapResource) { 71 bitmapResource->pixelRef()->globalRef(); 72 SkSafeRef(bitmapResource->getColorTable()); 73 incrementRefcount((void*) bitmapResource, kBitmap); 74} 75 76void ResourceCache::incrementRefcount(const SkPath* pathResource) { 77 incrementRefcount((void*) pathResource, kPath); 78} 79 80void ResourceCache::incrementRefcount(const Res_png_9patch* patchResource) { 81 incrementRefcount((void*) patchResource, kNinePatch); 82} 83 84void ResourceCache::incrementRefcountLocked(void* resource, ResourceType resourceType) { 85 ssize_t index = mCache->indexOfKey(resource); 86 ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL; 87 if (ref == NULL || mCache->size() == 0) { 88 ref = new ResourceReference(resourceType); 89 mCache->add(resource, ref); 90 } 91 ref->refCount++; 92} 93 94void ResourceCache::incrementRefcountLocked(const SkBitmap* bitmapResource) { 95 bitmapResource->pixelRef()->globalRef(); 96 SkSafeRef(bitmapResource->getColorTable()); 97 incrementRefcountLocked((void*) bitmapResource, kBitmap); 98} 99 100void ResourceCache::incrementRefcountLocked(const SkPath* pathResource) { 101 incrementRefcountLocked((void*) pathResource, kPath); 102} 103 104void ResourceCache::incrementRefcountLocked(const Res_png_9patch* patchResource) { 105 incrementRefcountLocked((void*) patchResource, kNinePatch); 106} 107 108void ResourceCache::decrementRefcount(void* resource) { 109 Mutex::Autolock _l(mLock); 110 decrementRefcountLocked(resource); 111} 112 113void ResourceCache::decrementRefcount(const SkBitmap* bitmapResource) { 114 bitmapResource->pixelRef()->globalUnref(); 115 SkSafeUnref(bitmapResource->getColorTable()); 116 decrementRefcount((void*) bitmapResource); 117} 118 119void ResourceCache::decrementRefcount(const SkPath* pathResource) { 120 decrementRefcount((void*) pathResource); 121} 122 123void ResourceCache::decrementRefcount(const Res_png_9patch* patchResource) { 124 decrementRefcount((void*) patchResource); 125} 126 127void ResourceCache::decrementRefcountLocked(void* resource) { 128 ssize_t index = mCache->indexOfKey(resource); 129 ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL; 130 if (ref == NULL) { 131 // Should not get here - shouldn't get a call to decrement if we're not yet tracking it 132 return; 133 } 134 ref->refCount--; 135 if (ref->refCount == 0) { 136 deleteResourceReferenceLocked(resource, ref); 137 } 138} 139 140void ResourceCache::decrementRefcountLocked(const SkBitmap* bitmapResource) { 141 bitmapResource->pixelRef()->globalUnref(); 142 SkSafeUnref(bitmapResource->getColorTable()); 143 decrementRefcountLocked((void*) bitmapResource); 144} 145 146void ResourceCache::decrementRefcountLocked(const SkPath* pathResource) { 147 decrementRefcountLocked((void*) pathResource); 148} 149 150void ResourceCache::decrementRefcountLocked(const Res_png_9patch* patchResource) { 151 decrementRefcountLocked((void*) patchResource); 152} 153 154void ResourceCache::destructor(SkPath* resource) { 155 Mutex::Autolock _l(mLock); 156 destructorLocked(resource); 157} 158 159void ResourceCache::destructorLocked(SkPath* resource) { 160 ssize_t index = mCache->indexOfKey(resource); 161 ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL; 162 if (ref == NULL) { 163 // If we're not tracking this resource, just delete it 164 if (Caches::hasInstance()) { 165 Caches::getInstance().pathCache.removeDeferred(resource); 166 } else { 167 delete resource; 168 } 169 return; 170 } 171 ref->destroyed = true; 172 if (ref->refCount == 0) { 173 deleteResourceReferenceLocked(resource, ref); 174 } 175} 176 177void ResourceCache::destructor(const SkBitmap* resource) { 178 Mutex::Autolock _l(mLock); 179 destructorLocked(resource); 180} 181 182void ResourceCache::destructorLocked(const SkBitmap* resource) { 183 ssize_t index = mCache->indexOfKey(resource); 184 ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL; 185 if (ref == NULL) { 186 // If we're not tracking this resource, just delete it 187 if (Caches::hasInstance()) { 188 Caches::getInstance().textureCache.releaseTexture(resource); 189 } 190 delete resource; 191 return; 192 } 193 ref->destroyed = true; 194 if (ref->refCount == 0) { 195 deleteResourceReferenceLocked(resource, ref); 196 } 197} 198 199void ResourceCache::destructor(Res_png_9patch* resource) { 200 Mutex::Autolock _l(mLock); 201 destructorLocked(resource); 202} 203 204void ResourceCache::destructorLocked(Res_png_9patch* resource) { 205 ssize_t index = mCache->indexOfKey(resource); 206 ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL; 207 if (ref == NULL) { 208 // If we're not tracking this resource, just delete it 209 if (Caches::hasInstance()) { 210 Caches::getInstance().patchCache.removeDeferred(resource); 211 } else { 212 // A Res_png_9patch is actually an array of byte that's larger 213 // than sizeof(Res_png_9patch). It must be freed as an array. 214 delete[] (int8_t*) resource; 215 } 216 return; 217 } 218 ref->destroyed = true; 219 if (ref->refCount == 0) { 220 deleteResourceReferenceLocked(resource, ref); 221 } 222} 223 224/** 225 * Return value indicates whether resource was actually recycled, which happens when RefCnt 226 * reaches 0. 227 */ 228bool ResourceCache::recycle(SkBitmap* resource) { 229 Mutex::Autolock _l(mLock); 230 return recycleLocked(resource); 231} 232 233/** 234 * Return value indicates whether resource was actually recycled, which happens when RefCnt 235 * reaches 0. 236 */ 237bool ResourceCache::recycleLocked(SkBitmap* resource) { 238 ssize_t index = mCache->indexOfKey(resource); 239 if (index < 0) { 240 if (Caches::hasInstance()) { 241 Caches::getInstance().textureCache.releaseTexture(resource); 242 } 243 // not tracking this resource; just recycle the pixel data 244 resource->setPixels(NULL, NULL); 245 return true; 246 } 247 ResourceReference* ref = mCache->valueAt(index); 248 if (ref == NULL) { 249 // Should not get here - shouldn't get a call to recycle if we're not yet tracking it 250 return true; 251 } 252 ref->recycled = true; 253 if (ref->refCount == 0) { 254 deleteResourceReferenceLocked(resource, ref); 255 return true; 256 } 257 // Still referring to resource, don't recycle yet 258 return false; 259} 260 261/** 262 * This method should only be called while the mLock mutex is held (that mutex is grabbed 263 * by the various destructor() and recycle() methods which call this method). 264 */ 265void ResourceCache::deleteResourceReferenceLocked(const void* resource, ResourceReference* ref) { 266 if (ref->recycled && ref->resourceType == kBitmap) { 267 SkBitmap* bitmap = (SkBitmap*) resource; 268 if (Caches::hasInstance()) { 269 Caches::getInstance().textureCache.releaseTexture(bitmap); 270 } 271 bitmap->setPixels(NULL, NULL); 272 } 273 if (ref->destroyed) { 274 switch (ref->resourceType) { 275 case kBitmap: { 276 SkBitmap* bitmap = (SkBitmap*) resource; 277 if (Caches::hasInstance()) { 278 Caches::getInstance().textureCache.releaseTexture(bitmap); 279 } 280 delete bitmap; 281 } 282 break; 283 case kPath: { 284 SkPath* path = (SkPath*) resource; 285 if (Caches::hasInstance()) { 286 Caches::getInstance().pathCache.removeDeferred(path); 287 } else { 288 delete path; 289 } 290 } 291 break; 292 case kNinePatch: { 293 if (Caches::hasInstance()) { 294 Caches::getInstance().patchCache.removeDeferred((Res_png_9patch*) resource); 295 } else { 296 // A Res_png_9patch is actually an array of byte that's larger 297 // than sizeof(Res_png_9patch). It must be freed as an array. 298 int8_t* patch = (int8_t*) resource; 299 delete[] patch; 300 } 301 } 302 break; 303 } 304 } 305 mCache->removeItem(resource); 306 delete ref; 307} 308 309}; // namespace uirenderer 310}; // namespace android 311