ResourceCache.cpp revision f5df700e6ce056ebfa322314d970e52d6facc35a
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<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(SkBitmap* bitmapResource) { 65 bitmapResource->pixelRef()->globalRef(); 66 SkSafeRef(bitmapResource->getColorTable()); 67 incrementRefcount((void*) bitmapResource, kBitmap); 68} 69 70void ResourceCache::incrementRefcount(SkPath* pathResource) { 71 incrementRefcount((void*) pathResource, kPath); 72} 73 74void ResourceCache::incrementRefcount(SkiaShader* shaderResource) { 75 SkSafeRef(shaderResource->getSkShader()); 76 incrementRefcount((void*) shaderResource, kShader); 77} 78 79void ResourceCache::incrementRefcount(SkiaColorFilter* filterResource) { 80 SkSafeRef(filterResource->getSkColorFilter()); 81 incrementRefcount((void*) filterResource, kColorFilter); 82} 83 84void ResourceCache::incrementRefcount(Res_png_9patch* patchResource) { 85 incrementRefcount((void*) patchResource, kNinePatch); 86} 87 88void ResourceCache::incrementRefcount(Layer* layerResource) { 89 incrementRefcount((void*) layerResource, kLayer); 90} 91 92void ResourceCache::incrementRefcountLocked(void* resource, ResourceType resourceType) { 93 ssize_t index = mCache->indexOfKey(resource); 94 ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL; 95 if (ref == NULL || mCache->size() == 0) { 96 ref = new ResourceReference(resourceType); 97 mCache->add(resource, ref); 98 } 99 ref->refCount++; 100} 101 102void ResourceCache::incrementRefcountLocked(SkBitmap* bitmapResource) { 103 bitmapResource->pixelRef()->globalRef(); 104 SkSafeRef(bitmapResource->getColorTable()); 105 incrementRefcountLocked((void*) bitmapResource, kBitmap); 106} 107 108void ResourceCache::incrementRefcountLocked(SkPath* pathResource) { 109 incrementRefcountLocked((void*) pathResource, kPath); 110} 111 112void ResourceCache::incrementRefcountLocked(SkiaShader* shaderResource) { 113 SkSafeRef(shaderResource->getSkShader()); 114 incrementRefcountLocked((void*) shaderResource, kShader); 115} 116 117void ResourceCache::incrementRefcountLocked(SkiaColorFilter* filterResource) { 118 SkSafeRef(filterResource->getSkColorFilter()); 119 incrementRefcountLocked((void*) filterResource, kColorFilter); 120} 121 122void ResourceCache::incrementRefcountLocked(Res_png_9patch* patchResource) { 123 incrementRefcountLocked((void*) patchResource, kNinePatch); 124} 125 126void ResourceCache::incrementRefcountLocked(Layer* layerResource) { 127 incrementRefcountLocked((void*) layerResource, kLayer); 128} 129 130void ResourceCache::decrementRefcount(void* resource) { 131 Mutex::Autolock _l(mLock); 132 decrementRefcountLocked(resource); 133} 134 135void ResourceCache::decrementRefcount(SkBitmap* bitmapResource) { 136 bitmapResource->pixelRef()->globalUnref(); 137 SkSafeUnref(bitmapResource->getColorTable()); 138 decrementRefcount((void*) bitmapResource); 139} 140 141void ResourceCache::decrementRefcount(SkPath* pathResource) { 142 decrementRefcount((void*) pathResource); 143} 144 145void ResourceCache::decrementRefcount(SkiaShader* shaderResource) { 146 SkSafeUnref(shaderResource->getSkShader()); 147 decrementRefcount((void*) shaderResource); 148} 149 150void ResourceCache::decrementRefcount(SkiaColorFilter* filterResource) { 151 SkSafeUnref(filterResource->getSkColorFilter()); 152 decrementRefcount((void*) filterResource); 153} 154 155void ResourceCache::decrementRefcount(Res_png_9patch* patchResource) { 156 decrementRefcount((void*) patchResource); 157} 158 159void ResourceCache::decrementRefcount(Layer* layerResource) { 160 decrementRefcount((void*) layerResource); 161} 162 163void ResourceCache::decrementRefcountLocked(void* resource) { 164 ssize_t index = mCache->indexOfKey(resource); 165 ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL; 166 if (ref == NULL) { 167 // Should not get here - shouldn't get a call to decrement if we're not yet tracking it 168 return; 169 } 170 ref->refCount--; 171 if (ref->refCount == 0) { 172 deleteResourceReferenceLocked(resource, ref); 173 } 174} 175 176void ResourceCache::decrementRefcountLocked(SkBitmap* bitmapResource) { 177 bitmapResource->pixelRef()->globalUnref(); 178 SkSafeUnref(bitmapResource->getColorTable()); 179 decrementRefcountLocked((void*) bitmapResource); 180} 181 182void ResourceCache::decrementRefcountLocked(SkPath* pathResource) { 183 decrementRefcountLocked((void*) pathResource); 184} 185 186void ResourceCache::decrementRefcountLocked(SkiaShader* shaderResource) { 187 SkSafeUnref(shaderResource->getSkShader()); 188 decrementRefcountLocked((void*) shaderResource); 189} 190 191void ResourceCache::decrementRefcountLocked(SkiaColorFilter* filterResource) { 192 SkSafeUnref(filterResource->getSkColorFilter()); 193 decrementRefcountLocked((void*) filterResource); 194} 195 196void ResourceCache::decrementRefcountLocked(Res_png_9patch* patchResource) { 197 decrementRefcountLocked((void*) patchResource); 198} 199 200void ResourceCache::decrementRefcountLocked(Layer* layerResource) { 201 decrementRefcountLocked((void*) layerResource); 202} 203 204void ResourceCache::destructor(SkPath* resource) { 205 Mutex::Autolock _l(mLock); 206 destructorLocked(resource); 207} 208 209void ResourceCache::destructorLocked(SkPath* resource) { 210 ssize_t index = mCache->indexOfKey(resource); 211 ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL; 212 if (ref == NULL) { 213 // If we're not tracking this resource, just delete it 214 if (Caches::hasInstance()) { 215 Caches::getInstance().pathCache.removeDeferred(resource); 216 } else { 217 delete resource; 218 } 219 return; 220 } 221 ref->destroyed = true; 222 if (ref->refCount == 0) { 223 deleteResourceReferenceLocked(resource, ref); 224 } 225} 226 227void ResourceCache::destructor(SkBitmap* resource) { 228 Mutex::Autolock _l(mLock); 229 destructorLocked(resource); 230} 231 232void ResourceCache::destructorLocked(SkBitmap* resource) { 233 ssize_t index = mCache->indexOfKey(resource); 234 ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL; 235 if (ref == NULL) { 236 // If we're not tracking this resource, just delete it 237 if (Caches::hasInstance()) { 238 Caches::getInstance().textureCache.removeDeferred(resource); 239 } else { 240 delete resource; 241 } 242 return; 243 } 244 ref->destroyed = true; 245 if (ref->refCount == 0) { 246 deleteResourceReferenceLocked(resource, ref); 247 } 248} 249 250void ResourceCache::destructor(SkiaShader* resource) { 251 Mutex::Autolock _l(mLock); 252 destructorLocked(resource); 253} 254 255void ResourceCache::destructorLocked(SkiaShader* resource) { 256 ssize_t index = mCache->indexOfKey(resource); 257 ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL; 258 if (ref == NULL) { 259 // If we're not tracking this resource, just delete it 260 delete resource; 261 return; 262 } 263 ref->destroyed = true; 264 if (ref->refCount == 0) { 265 deleteResourceReferenceLocked(resource, ref); 266 } 267} 268 269void ResourceCache::destructor(SkiaColorFilter* resource) { 270 Mutex::Autolock _l(mLock); 271 destructorLocked(resource); 272} 273 274void ResourceCache::destructorLocked(SkiaColorFilter* resource) { 275 ssize_t index = mCache->indexOfKey(resource); 276 ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL; 277 if (ref == NULL) { 278 // If we're not tracking this resource, just delete it 279 delete resource; 280 return; 281 } 282 ref->destroyed = true; 283 if (ref->refCount == 0) { 284 deleteResourceReferenceLocked(resource, ref); 285 } 286} 287 288void ResourceCache::destructor(Res_png_9patch* resource) { 289 Mutex::Autolock _l(mLock); 290 destructorLocked(resource); 291} 292 293void ResourceCache::destructorLocked(Res_png_9patch* resource) { 294 ssize_t index = mCache->indexOfKey(resource); 295 ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL; 296 if (ref == NULL) { 297 // If we're not tracking this resource, just delete it 298 if (Caches::hasInstance()) { 299 Caches::getInstance().patchCache.removeDeferred(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 delete[] (int8_t*) resource; 304 } 305 return; 306 } 307 ref->destroyed = true; 308 if (ref->refCount == 0) { 309 deleteResourceReferenceLocked(resource, ref); 310 } 311} 312 313/** 314 * Return value indicates whether resource was actually recycled, which happens when RefCnt 315 * reaches 0. 316 */ 317bool ResourceCache::recycle(SkBitmap* resource) { 318 Mutex::Autolock _l(mLock); 319 return recycleLocked(resource); 320} 321 322/** 323 * Return value indicates whether resource was actually recycled, which happens when RefCnt 324 * reaches 0. 325 */ 326bool ResourceCache::recycleLocked(SkBitmap* resource) { 327 ssize_t index = mCache->indexOfKey(resource); 328 if (index < 0) { 329 // not tracking this resource; just recycle the pixel data 330 resource->setPixels(NULL, NULL); 331 return true; 332 } 333 ResourceReference* ref = mCache->valueAt(index); 334 if (ref == NULL) { 335 // Should not get here - shouldn't get a call to recycle if we're not yet tracking it 336 return true; 337 } 338 ref->recycled = true; 339 if (ref->refCount == 0) { 340 deleteResourceReferenceLocked(resource, ref); 341 return true; 342 } 343 // Still referring to resource, don't recycle yet 344 return false; 345} 346 347/** 348 * This method should only be called while the mLock mutex is held (that mutex is grabbed 349 * by the various destructor() and recycle() methods which call this method). 350 */ 351void ResourceCache::deleteResourceReferenceLocked(void* resource, ResourceReference* ref) { 352 if (ref->recycled && ref->resourceType == kBitmap) { 353 ((SkBitmap*) resource)->setPixels(NULL, NULL); 354 } 355 if (ref->destroyed || ref->resourceType == kLayer) { 356 switch (ref->resourceType) { 357 case kBitmap: { 358 SkBitmap* bitmap = (SkBitmap*) resource; 359 if (Caches::hasInstance()) { 360 Caches::getInstance().textureCache.removeDeferred(bitmap); 361 } else { 362 delete bitmap; 363 } 364 } 365 break; 366 case kPath: { 367 SkPath* path = (SkPath*) resource; 368 if (Caches::hasInstance()) { 369 Caches::getInstance().pathCache.removeDeferred(path); 370 } else { 371 delete path; 372 } 373 } 374 break; 375 case kShader: { 376 SkiaShader* shader = (SkiaShader*) resource; 377 delete shader; 378 } 379 break; 380 case kColorFilter: { 381 SkiaColorFilter* filter = (SkiaColorFilter*) resource; 382 delete filter; 383 } 384 break; 385 case kNinePatch: { 386 if (Caches::hasInstance()) { 387 Caches::getInstance().patchCache.removeDeferred((Res_png_9patch*) resource); 388 } else { 389 // A Res_png_9patch is actually an array of byte that's larger 390 // than sizeof(Res_png_9patch). It must be freed as an array. 391 int8_t* patch = (int8_t*) resource; 392 delete[] patch; 393 } 394 } 395 break; 396 case kLayer: { 397 Layer* layer = (Layer*) resource; 398 Caches::getInstance().deleteLayerDeferred(layer); 399 } 400 break; 401 } 402 } 403 mCache->removeItem(resource); 404 delete ref; 405} 406 407}; // namespace uirenderer 408}; // namespace android 409