ResourceCache.cpp revision a35778c799e8073a42b9e22191bde9d838327ab7
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.removeDeferred(resource); 189 } else { 190 delete resource; 191 } 192 return; 193 } 194 ref->destroyed = true; 195 if (ref->refCount == 0) { 196 deleteResourceReferenceLocked(resource, ref); 197 } 198} 199 200void ResourceCache::destructor(Res_png_9patch* resource) { 201 Mutex::Autolock _l(mLock); 202 destructorLocked(resource); 203} 204 205void ResourceCache::destructorLocked(Res_png_9patch* resource) { 206 ssize_t index = mCache->indexOfKey(resource); 207 ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL; 208 if (ref == NULL) { 209 // If we're not tracking this resource, just delete it 210 if (Caches::hasInstance()) { 211 Caches::getInstance().patchCache.removeDeferred(resource); 212 } else { 213 // A Res_png_9patch is actually an array of byte that's larger 214 // than sizeof(Res_png_9patch). It must be freed as an array. 215 delete[] (int8_t*) resource; 216 } 217 return; 218 } 219 ref->destroyed = true; 220 if (ref->refCount == 0) { 221 deleteResourceReferenceLocked(resource, ref); 222 } 223} 224 225/** 226 * Return value indicates whether resource was actually recycled, which happens when RefCnt 227 * reaches 0. 228 */ 229bool ResourceCache::recycle(SkBitmap* resource) { 230 Mutex::Autolock _l(mLock); 231 return recycleLocked(resource); 232} 233 234/** 235 * Return value indicates whether resource was actually recycled, which happens when RefCnt 236 * reaches 0. 237 */ 238bool ResourceCache::recycleLocked(SkBitmap* resource) { 239 ssize_t index = mCache->indexOfKey(resource); 240 if (index < 0) { 241 // not tracking this resource; just recycle the pixel data 242 resource->setPixels(NULL, NULL); 243 return true; 244 } 245 ResourceReference* ref = mCache->valueAt(index); 246 if (ref == NULL) { 247 // Should not get here - shouldn't get a call to recycle if we're not yet tracking it 248 return true; 249 } 250 ref->recycled = true; 251 if (ref->refCount == 0) { 252 deleteResourceReferenceLocked(resource, ref); 253 return true; 254 } 255 // Still referring to resource, don't recycle yet 256 return false; 257} 258 259/** 260 * This method should only be called while the mLock mutex is held (that mutex is grabbed 261 * by the various destructor() and recycle() methods which call this method). 262 */ 263void ResourceCache::deleteResourceReferenceLocked(const void* resource, ResourceReference* ref) { 264 if (ref->recycled && ref->resourceType == kBitmap) { 265 ((SkBitmap*) resource)->setPixels(NULL, NULL); 266 } 267 if (ref->destroyed) { 268 switch (ref->resourceType) { 269 case kBitmap: { 270 SkBitmap* bitmap = (SkBitmap*) resource; 271 if (Caches::hasInstance()) { 272 Caches::getInstance().textureCache.removeDeferred(bitmap); 273 } else { 274 delete bitmap; 275 } 276 } 277 break; 278 case kPath: { 279 SkPath* path = (SkPath*) resource; 280 if (Caches::hasInstance()) { 281 Caches::getInstance().pathCache.removeDeferred(path); 282 } else { 283 delete path; 284 } 285 } 286 break; 287 case kNinePatch: { 288 if (Caches::hasInstance()) { 289 Caches::getInstance().patchCache.removeDeferred((Res_png_9patch*) resource); 290 } else { 291 // A Res_png_9patch is actually an array of byte that's larger 292 // than sizeof(Res_png_9patch). It must be freed as an array. 293 int8_t* patch = (int8_t*) resource; 294 delete[] patch; 295 } 296 } 297 break; 298 } 299 } 300 mCache->removeItem(resource); 301 delete ref; 302} 303 304}; // namespace uirenderer 305}; // namespace android 306