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#include <SkPixelRef.h> 18#include "ResourceCache.h" 19#include "Caches.h" 20 21namespace android { 22namespace uirenderer { 23 24/////////////////////////////////////////////////////////////////////////////// 25// Resource cache 26/////////////////////////////////////////////////////////////////////////////// 27 28void ResourceCache::logCache() { 29 ALOGD("ResourceCache: cacheReport:"); 30 for (size_t i = 0; i < mCache->size(); ++i) { 31 ResourceReference* ref = mCache->valueAt(i); 32 ALOGD(" ResourceCache: mCache(%d): resource, ref = 0x%p, 0x%p", 33 i, mCache->keyAt(i), mCache->valueAt(i)); 34 ALOGD(" ResourceCache: mCache(%d): refCount, recycled, destroyed, type = %d, %d, %d, %d", 35 i, ref->refCount, ref->recycled, ref->destroyed, ref->resourceType); 36 } 37} 38 39ResourceCache::ResourceCache() { 40 Mutex::Autolock _l(mLock); 41 mCache = new KeyedVector<void*, ResourceReference*>(); 42} 43 44ResourceCache::~ResourceCache() { 45 Mutex::Autolock _l(mLock); 46 delete mCache; 47} 48 49void ResourceCache::lock() { 50 mLock.lock(); 51} 52 53void ResourceCache::unlock() { 54 mLock.unlock(); 55} 56 57void ResourceCache::incrementRefcount(void* resource, ResourceType resourceType) { 58 Mutex::Autolock _l(mLock); 59 incrementRefcountLocked(resource, resourceType); 60} 61 62void ResourceCache::incrementRefcount(SkBitmap* bitmapResource) { 63 SkSafeRef(bitmapResource->pixelRef()); 64 SkSafeRef(bitmapResource->getColorTable()); 65 incrementRefcount((void*) bitmapResource, kBitmap); 66} 67 68void ResourceCache::incrementRefcount(SkPath* pathResource) { 69 incrementRefcount((void*) pathResource, kPath); 70} 71 72void ResourceCache::incrementRefcount(SkiaShader* shaderResource) { 73 SkSafeRef(shaderResource->getSkShader()); 74 incrementRefcount((void*) shaderResource, kShader); 75} 76 77void ResourceCache::incrementRefcount(SkiaColorFilter* filterResource) { 78 SkSafeRef(filterResource->getSkColorFilter()); 79 incrementRefcount((void*) filterResource, kColorFilter); 80} 81 82void ResourceCache::incrementRefcount(Layer* layerResource) { 83 incrementRefcount((void*) layerResource, kLayer); 84} 85 86void ResourceCache::incrementRefcountLocked(void* resource, ResourceType resourceType) { 87 ssize_t index = mCache->indexOfKey(resource); 88 ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL; 89 if (ref == NULL || mCache->size() == 0) { 90 ref = new ResourceReference(resourceType); 91 mCache->add(resource, ref); 92 } 93 ref->refCount++; 94} 95 96void ResourceCache::incrementRefcountLocked(SkBitmap* bitmapResource) { 97 SkSafeRef(bitmapResource->pixelRef()); 98 SkSafeRef(bitmapResource->getColorTable()); 99 incrementRefcountLocked((void*) bitmapResource, kBitmap); 100} 101 102void ResourceCache::incrementRefcountLocked(SkPath* pathResource) { 103 incrementRefcountLocked((void*) pathResource, kPath); 104} 105 106void ResourceCache::incrementRefcountLocked(SkiaShader* shaderResource) { 107 SkSafeRef(shaderResource->getSkShader()); 108 incrementRefcountLocked((void*) shaderResource, kShader); 109} 110 111void ResourceCache::incrementRefcountLocked(SkiaColorFilter* filterResource) { 112 SkSafeRef(filterResource->getSkColorFilter()); 113 incrementRefcountLocked((void*) filterResource, kColorFilter); 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(SkBitmap* bitmapResource) { 126 SkSafeUnref(bitmapResource->pixelRef()); 127 SkSafeUnref(bitmapResource->getColorTable()); 128 decrementRefcount((void*) bitmapResource); 129} 130 131void ResourceCache::decrementRefcount(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(SkiaColorFilter* filterResource) { 141 SkSafeUnref(filterResource->getSkColorFilter()); 142 decrementRefcount((void*) filterResource); 143} 144 145void ResourceCache::decrementRefcount(Layer* layerResource) { 146 decrementRefcount((void*) layerResource); 147} 148 149void ResourceCache::decrementRefcountLocked(void* resource) { 150 ssize_t index = mCache->indexOfKey(resource); 151 ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL; 152 if (ref == NULL) { 153 // Should not get here - shouldn't get a call to decrement if we're not yet tracking it 154 return; 155 } 156 ref->refCount--; 157 if (ref->refCount == 0) { 158 deleteResourceReferenceLocked(resource, ref); 159 } 160} 161 162void ResourceCache::decrementRefcountLocked(SkBitmap* bitmapResource) { 163 SkSafeUnref(bitmapResource->pixelRef()); 164 SkSafeUnref(bitmapResource->getColorTable()); 165 decrementRefcountLocked((void*) bitmapResource); 166} 167 168void ResourceCache::decrementRefcountLocked(SkPath* pathResource) { 169 decrementRefcountLocked((void*) pathResource); 170} 171 172void ResourceCache::decrementRefcountLocked(SkiaShader* shaderResource) { 173 SkSafeUnref(shaderResource->getSkShader()); 174 decrementRefcountLocked((void*) shaderResource); 175} 176 177void ResourceCache::decrementRefcountLocked(SkiaColorFilter* filterResource) { 178 SkSafeUnref(filterResource->getSkColorFilter()); 179 decrementRefcountLocked((void*) filterResource); 180} 181 182void ResourceCache::decrementRefcountLocked(Layer* layerResource) { 183 decrementRefcountLocked((void*) layerResource); 184} 185 186void ResourceCache::destructor(SkPath* resource) { 187 Mutex::Autolock _l(mLock); 188 destructorLocked(resource); 189} 190 191void ResourceCache::destructorLocked(SkPath* resource) { 192 ssize_t index = mCache->indexOfKey(resource); 193 ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL; 194 if (ref == NULL) { 195 // If we're not tracking this resource, just delete it 196 if (Caches::hasInstance()) { 197 Caches::getInstance().pathCache.removeDeferred(resource); 198 } 199 delete resource; 200 return; 201 } 202 ref->destroyed = true; 203 if (ref->refCount == 0) { 204 deleteResourceReferenceLocked(resource, ref); 205 } 206} 207 208void ResourceCache::destructor(SkBitmap* resource) { 209 Mutex::Autolock _l(mLock); 210 destructorLocked(resource); 211} 212 213void ResourceCache::destructorLocked(SkBitmap* resource) { 214 ssize_t index = mCache->indexOfKey(resource); 215 ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL; 216 if (ref == NULL) { 217 // If we're not tracking this resource, just delete it 218 if (Caches::hasInstance()) { 219 Caches::getInstance().textureCache.removeDeferred(resource); 220 } 221 delete resource; 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(SkiaColorFilter* resource) { 250 Mutex::Autolock _l(mLock); 251 destructorLocked(resource); 252} 253 254void ResourceCache::destructorLocked(SkiaColorFilter* 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 delete resource; 260 return; 261 } 262 ref->destroyed = true; 263 if (ref->refCount == 0) { 264 deleteResourceReferenceLocked(resource, ref); 265 } 266} 267 268/** 269 * Return value indicates whether resource was actually recycled, which happens when RefCnt 270 * reaches 0. 271 */ 272bool ResourceCache::recycle(SkBitmap* resource) { 273 Mutex::Autolock _l(mLock); 274 return recycleLocked(resource); 275} 276 277/** 278 * Return value indicates whether resource was actually recycled, which happens when RefCnt 279 * reaches 0. 280 */ 281bool ResourceCache::recycleLocked(SkBitmap* resource) { 282 ssize_t index = mCache->indexOfKey(resource); 283 if (index < 0) { 284 // not tracking this resource; just recycle the pixel data 285 resource->setPixels(NULL, NULL); 286 return true; 287 } 288 ResourceReference* ref = mCache->valueAt(index); 289 if (ref == NULL) { 290 // Should not get here - shouldn't get a call to recycle if we're not yet tracking it 291 return true; 292 } 293 ref->recycled = true; 294 if (ref->refCount == 0) { 295 deleteResourceReferenceLocked(resource, ref); 296 return true; 297 } 298 // Still referring to resource, don't recycle yet 299 return false; 300} 301 302/** 303 * This method should only be called while the mLock mutex is held (that mutex is grabbed 304 * by the various destructor() and recycle() methods which call this method). 305 */ 306void ResourceCache::deleteResourceReferenceLocked(void* resource, ResourceReference* ref) { 307 if (ref->recycled && ref->resourceType == kBitmap) { 308 ((SkBitmap*) resource)->setPixels(NULL, NULL); 309 } 310 if (ref->destroyed || ref->resourceType == kLayer) { 311 switch (ref->resourceType) { 312 case kBitmap: { 313 SkBitmap* bitmap = (SkBitmap*) resource; 314 if (Caches::hasInstance()) { 315 Caches::getInstance().textureCache.removeDeferred(bitmap); 316 } 317 delete bitmap; 318 } 319 break; 320 case kPath: { 321 SkPath* path = (SkPath*) resource; 322 if (Caches::hasInstance()) { 323 Caches::getInstance().pathCache.removeDeferred(path); 324 } 325 delete path; 326 } 327 break; 328 case kShader: { 329 SkiaShader* shader = (SkiaShader*) resource; 330 delete shader; 331 } 332 break; 333 case kColorFilter: { 334 SkiaColorFilter* filter = (SkiaColorFilter*) resource; 335 delete filter; 336 } 337 break; 338 case kLayer: { 339 Layer* layer = (Layer*) resource; 340 Caches::getInstance().deleteLayerDeferred(layer); 341 } 342 break; 343 } 344 } 345 mCache->removeItem(resource); 346 delete ref; 347} 348 349}; // namespace uirenderer 350}; // namespace android 351