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