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 23 namespace android { 24 namespace uirenderer { 25 26 /////////////////////////////////////////////////////////////////////////////// 27 // Resource cache 28 /////////////////////////////////////////////////////////////////////////////// 29 30 void 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 41 ResourceCache::ResourceCache() { 42 Mutex::Autolock _l(mLock); 43 mCache = new KeyedVector<void*, ResourceReference*>(); 44 } 45 46 ResourceCache::~ResourceCache() { 47 Mutex::Autolock _l(mLock); 48 delete mCache; 49 } 50 51 void ResourceCache::lock() { 52 mLock.lock(); 53 } 54 55 void ResourceCache::unlock() { 56 mLock.unlock(); 57 } 58 59 void ResourceCache::incrementRefcount(void* resource, ResourceType resourceType) { 60 Mutex::Autolock _l(mLock); 61 incrementRefcountLocked(resource, resourceType); 62 } 63 64 void ResourceCache::incrementRefcount(SkBitmap* bitmapResource) { 65 bitmapResource->pixelRef()->globalRef(); 66 SkSafeRef(bitmapResource->getColorTable()); 67 incrementRefcount((void*) bitmapResource, kBitmap); 68 } 69 70 void ResourceCache::incrementRefcount(SkPath* pathResource) { 71 incrementRefcount((void*) pathResource, kPath); 72 } 73 74 void ResourceCache::incrementRefcount(SkiaShader* shaderResource) { 75 SkSafeRef(shaderResource->getSkShader()); 76 incrementRefcount((void*) shaderResource, kShader); 77 } 78 79 void ResourceCache::incrementRefcount(SkiaColorFilter* filterResource) { 80 SkSafeRef(filterResource->getSkColorFilter()); 81 incrementRefcount((void*) filterResource, kColorFilter); 82 } 83 84 void ResourceCache::incrementRefcount(Res_png_9patch* patchResource) { 85 incrementRefcount((void*) patchResource, kNinePatch); 86 } 87 88 void ResourceCache::incrementRefcount(Layer* layerResource) { 89 incrementRefcount((void*) layerResource, kLayer); 90 } 91 92 void 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 102 void ResourceCache::incrementRefcountLocked(SkBitmap* bitmapResource) { 103 bitmapResource->pixelRef()->globalRef(); 104 SkSafeRef(bitmapResource->getColorTable()); 105 incrementRefcountLocked((void*) bitmapResource, kBitmap); 106 } 107 108 void ResourceCache::incrementRefcountLocked(SkPath* pathResource) { 109 incrementRefcountLocked((void*) pathResource, kPath); 110 } 111 112 void ResourceCache::incrementRefcountLocked(SkiaShader* shaderResource) { 113 SkSafeRef(shaderResource->getSkShader()); 114 incrementRefcountLocked((void*) shaderResource, kShader); 115 } 116 117 void ResourceCache::incrementRefcountLocked(SkiaColorFilter* filterResource) { 118 SkSafeRef(filterResource->getSkColorFilter()); 119 incrementRefcountLocked((void*) filterResource, kColorFilter); 120 } 121 122 void ResourceCache::incrementRefcountLocked(Res_png_9patch* patchResource) { 123 incrementRefcountLocked((void*) patchResource, kNinePatch); 124 } 125 126 void ResourceCache::incrementRefcountLocked(Layer* layerResource) { 127 incrementRefcountLocked((void*) layerResource, kLayer); 128 } 129 130 void ResourceCache::decrementRefcount(void* resource) { 131 Mutex::Autolock _l(mLock); 132 decrementRefcountLocked(resource); 133 } 134 135 void ResourceCache::decrementRefcount(SkBitmap* bitmapResource) { 136 bitmapResource->pixelRef()->globalUnref(); 137 SkSafeUnref(bitmapResource->getColorTable()); 138 decrementRefcount((void*) bitmapResource); 139 } 140 141 void ResourceCache::decrementRefcount(SkPath* pathResource) { 142 decrementRefcount((void*) pathResource); 143 } 144 145 void ResourceCache::decrementRefcount(SkiaShader* shaderResource) { 146 SkSafeUnref(shaderResource->getSkShader()); 147 decrementRefcount((void*) shaderResource); 148 } 149 150 void ResourceCache::decrementRefcount(SkiaColorFilter* filterResource) { 151 SkSafeUnref(filterResource->getSkColorFilter()); 152 decrementRefcount((void*) filterResource); 153 } 154 155 void ResourceCache::decrementRefcount(Res_png_9patch* patchResource) { 156 decrementRefcount((void*) patchResource); 157 } 158 159 void ResourceCache::decrementRefcount(Layer* layerResource) { 160 decrementRefcount((void*) layerResource); 161 } 162 163 void 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 176 void ResourceCache::decrementRefcountLocked(SkBitmap* bitmapResource) { 177 bitmapResource->pixelRef()->globalUnref(); 178 SkSafeUnref(bitmapResource->getColorTable()); 179 decrementRefcountLocked((void*) bitmapResource); 180 } 181 182 void ResourceCache::decrementRefcountLocked(SkPath* pathResource) { 183 decrementRefcountLocked((void*) pathResource); 184 } 185 186 void ResourceCache::decrementRefcountLocked(SkiaShader* shaderResource) { 187 SkSafeUnref(shaderResource->getSkShader()); 188 decrementRefcountLocked((void*) shaderResource); 189 } 190 191 void ResourceCache::decrementRefcountLocked(SkiaColorFilter* filterResource) { 192 SkSafeUnref(filterResource->getSkColorFilter()); 193 decrementRefcountLocked((void*) filterResource); 194 } 195 196 void ResourceCache::decrementRefcountLocked(Res_png_9patch* patchResource) { 197 decrementRefcountLocked((void*) patchResource); 198 } 199 200 void ResourceCache::decrementRefcountLocked(Layer* layerResource) { 201 decrementRefcountLocked((void*) layerResource); 202 } 203 204 void ResourceCache::destructor(SkPath* resource) { 205 Mutex::Autolock _l(mLock); 206 destructorLocked(resource); 207 } 208 209 void 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 226 void ResourceCache::destructor(SkBitmap* resource) { 227 Mutex::Autolock _l(mLock); 228 destructorLocked(resource); 229 } 230 231 void 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 248 void ResourceCache::destructor(SkiaShader* resource) { 249 Mutex::Autolock _l(mLock); 250 destructorLocked(resource); 251 } 252 253 void 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 267 void ResourceCache::destructor(SkiaColorFilter* resource) { 268 Mutex::Autolock _l(mLock); 269 destructorLocked(resource); 270 } 271 272 void 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 286 void ResourceCache::destructor(Res_png_9patch* resource) { 287 Mutex::Autolock _l(mLock); 288 destructorLocked(resource); 289 } 290 291 void 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 */ 314 bool 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 */ 323 bool 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 */ 348 void 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