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