ResourceCache.cpp revision 0c20c3898a533b7b76f60827cb6ea02e17c5953d
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(%d): resource, ref = 0x%p, 0x%p", 35 i, mCache->keyAt(i), mCache->valueAt(i)); 36 ALOGD(" ResourceCache: mCache(%d): 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 } 217 delete resource; 218 return; 219 } 220 ref->destroyed = true; 221 if (ref->refCount == 0) { 222 deleteResourceReferenceLocked(resource, ref); 223 } 224} 225 226void ResourceCache::destructor(SkBitmap* resource) { 227 Mutex::Autolock _l(mLock); 228 destructorLocked(resource); 229} 230 231void ResourceCache::destructorLocked(SkBitmap* resource) { 232 ssize_t index = mCache->indexOfKey(resource); 233 ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL; 234 if (ref == NULL) { 235 // If we're not tracking this resource, just delete it 236 if (Caches::hasInstance()) { 237 Caches::getInstance().textureCache.removeDeferred(resource); 238 } 239 delete resource; 240 return; 241 } 242 ref->destroyed = true; 243 if (ref->refCount == 0) { 244 deleteResourceReferenceLocked(resource, ref); 245 } 246} 247 248void ResourceCache::destructor(SkiaShader* resource) { 249 Mutex::Autolock _l(mLock); 250 destructorLocked(resource); 251} 252 253void ResourceCache::destructorLocked(SkiaShader* resource) { 254 ssize_t index = mCache->indexOfKey(resource); 255 ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL; 256 if (ref == NULL) { 257 // If we're not tracking this resource, just delete it 258 delete resource; 259 return; 260 } 261 ref->destroyed = true; 262 if (ref->refCount == 0) { 263 deleteResourceReferenceLocked(resource, ref); 264 } 265} 266 267void ResourceCache::destructor(SkiaColorFilter* resource) { 268 Mutex::Autolock _l(mLock); 269 destructorLocked(resource); 270} 271 272void ResourceCache::destructorLocked(SkiaColorFilter* resource) { 273 ssize_t index = mCache->indexOfKey(resource); 274 ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL; 275 if (ref == NULL) { 276 // If we're not tracking this resource, just delete it 277 delete resource; 278 return; 279 } 280 ref->destroyed = true; 281 if (ref->refCount == 0) { 282 deleteResourceReferenceLocked(resource, ref); 283 } 284} 285 286void ResourceCache::destructor(Res_png_9patch* resource) { 287 Mutex::Autolock _l(mLock); 288 destructorLocked(resource); 289} 290 291void ResourceCache::destructorLocked(Res_png_9patch* resource) { 292 ssize_t index = mCache->indexOfKey(resource); 293 ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL; 294 if (ref == NULL) { 295 if (Caches::hasInstance()) { 296 Caches::getInstance().patchCache.removeDeferred(resource); 297 } 298 // If we're not tracking this resource, just delete it 299 // A Res_png_9patch is actually an array of byte that's larger 300 // than sizeof(Res_png_9patch). It must be freed as an array. 301 delete[] (int8_t*) resource; 302 return; 303 } 304 ref->destroyed = true; 305 if (ref->refCount == 0) { 306 deleteResourceReferenceLocked(resource, ref); 307 } 308} 309 310/** 311 * Return value indicates whether resource was actually recycled, which happens when RefCnt 312 * reaches 0. 313 */ 314bool ResourceCache::recycle(SkBitmap* resource) { 315 Mutex::Autolock _l(mLock); 316 return recycleLocked(resource); 317} 318 319/** 320 * Return value indicates whether resource was actually recycled, which happens when RefCnt 321 * reaches 0. 322 */ 323bool ResourceCache::recycleLocked(SkBitmap* resource) { 324 ssize_t index = mCache->indexOfKey(resource); 325 if (index < 0) { 326 // not tracking this resource; just recycle the pixel data 327 resource->setPixels(NULL, NULL); 328 return true; 329 } 330 ResourceReference* ref = mCache->valueAt(index); 331 if (ref == NULL) { 332 // Should not get here - shouldn't get a call to recycle if we're not yet tracking it 333 return true; 334 } 335 ref->recycled = true; 336 if (ref->refCount == 0) { 337 deleteResourceReferenceLocked(resource, ref); 338 return true; 339 } 340 // Still referring to resource, don't recycle yet 341 return false; 342} 343 344/** 345 * This method should only be called while the mLock mutex is held (that mutex is grabbed 346 * by the various destructor() and recycle() methods which call this method). 347 */ 348void ResourceCache::deleteResourceReferenceLocked(void* resource, ResourceReference* ref) { 349 if (ref->recycled && ref->resourceType == kBitmap) { 350 ((SkBitmap*) resource)->setPixels(NULL, NULL); 351 } 352 if (ref->destroyed || ref->resourceType == kLayer) { 353 switch (ref->resourceType) { 354 case kBitmap: { 355 SkBitmap* bitmap = (SkBitmap*) resource; 356 if (Caches::hasInstance()) { 357 Caches::getInstance().textureCache.removeDeferred(bitmap); 358 } 359 delete bitmap; 360 } 361 break; 362 case kPath: { 363 SkPath* path = (SkPath*) resource; 364 if (Caches::hasInstance()) { 365 Caches::getInstance().pathCache.removeDeferred(path); 366 } 367 delete path; 368 } 369 break; 370 case kShader: { 371 SkiaShader* shader = (SkiaShader*) resource; 372 delete shader; 373 } 374 break; 375 case kColorFilter: { 376 SkiaColorFilter* filter = (SkiaColorFilter*) resource; 377 delete filter; 378 } 379 break; 380 case kNinePatch: { 381 if (Caches::hasInstance()) { 382 Caches::getInstance().patchCache.removeDeferred((Res_png_9patch*) resource); 383 } 384 // A Res_png_9patch is actually an array of byte that's larger 385 // than sizeof(Res_png_9patch). It must be freed as an array. 386 int8_t* patch = (int8_t*) resource; 387 delete[] patch; 388 } 389 break; 390 case kLayer: { 391 Layer* layer = (Layer*) resource; 392 Caches::getInstance().deleteLayerDeferred(layer); 393 } 394 break; 395 } 396 } 397 mCache->removeItem(resource); 398 delete ref; 399} 400 401}; // namespace uirenderer 402}; // namespace android 403