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 21 namespace android { 22 namespace uirenderer { 23 24 /////////////////////////////////////////////////////////////////////////////// 25 // Resource cache 26 /////////////////////////////////////////////////////////////////////////////// 27 28 void 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 39 ResourceCache::ResourceCache() { 40 Mutex::Autolock _l(mLock); 41 mCache = new KeyedVector<void*, ResourceReference*>(); 42 } 43 44 ResourceCache::~ResourceCache() { 45 Mutex::Autolock _l(mLock); 46 delete mCache; 47 } 48 49 void ResourceCache::lock() { 50 mLock.lock(); 51 } 52 53 void ResourceCache::unlock() { 54 mLock.unlock(); 55 } 56 57 void ResourceCache::incrementRefcount(void* resource, ResourceType resourceType) { 58 Mutex::Autolock _l(mLock); 59 incrementRefcountLocked(resource, resourceType); 60 } 61 62 void ResourceCache::incrementRefcount(SkBitmap* bitmapResource) { 63 SkSafeRef(bitmapResource->pixelRef()); 64 SkSafeRef(bitmapResource->getColorTable()); 65 incrementRefcount((void*) bitmapResource, kBitmap); 66 } 67 68 void ResourceCache::incrementRefcount(SkPath* pathResource) { 69 incrementRefcount((void*) pathResource, kPath); 70 } 71 72 void ResourceCache::incrementRefcount(SkiaShader* shaderResource) { 73 SkSafeRef(shaderResource->getSkShader()); 74 incrementRefcount((void*) shaderResource, kShader); 75 } 76 77 void ResourceCache::incrementRefcount(SkiaColorFilter* filterResource) { 78 SkSafeRef(filterResource->getSkColorFilter()); 79 incrementRefcount((void*) filterResource, kColorFilter); 80 } 81 82 void ResourceCache::incrementRefcount(Layer* layerResource) { 83 incrementRefcount((void*) layerResource, kLayer); 84 } 85 86 void 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 96 void ResourceCache::incrementRefcountLocked(SkBitmap* bitmapResource) { 97 SkSafeRef(bitmapResource->pixelRef()); 98 SkSafeRef(bitmapResource->getColorTable()); 99 incrementRefcountLocked((void*) bitmapResource, kBitmap); 100 } 101 102 void ResourceCache::incrementRefcountLocked(SkPath* pathResource) { 103 incrementRefcountLocked((void*) pathResource, kPath); 104 } 105 106 void ResourceCache::incrementRefcountLocked(SkiaShader* shaderResource) { 107 SkSafeRef(shaderResource->getSkShader()); 108 incrementRefcountLocked((void*) shaderResource, kShader); 109 } 110 111 void ResourceCache::incrementRefcountLocked(SkiaColorFilter* filterResource) { 112 SkSafeRef(filterResource->getSkColorFilter()); 113 incrementRefcountLocked((void*) filterResource, kColorFilter); 114 } 115 116 void ResourceCache::incrementRefcountLocked(Layer* layerResource) { 117 incrementRefcountLocked((void*) layerResource, kLayer); 118 } 119 120 void ResourceCache::decrementRefcount(void* resource) { 121 Mutex::Autolock _l(mLock); 122 decrementRefcountLocked(resource); 123 } 124 125 void ResourceCache::decrementRefcount(SkBitmap* bitmapResource) { 126 SkSafeUnref(bitmapResource->pixelRef()); 127 SkSafeUnref(bitmapResource->getColorTable()); 128 decrementRefcount((void*) bitmapResource); 129 } 130 131 void ResourceCache::decrementRefcount(SkPath* pathResource) { 132 decrementRefcount((void*) pathResource); 133 } 134 135 void ResourceCache::decrementRefcount(SkiaShader* shaderResource) { 136 SkSafeUnref(shaderResource->getSkShader()); 137 decrementRefcount((void*) shaderResource); 138 } 139 140 void ResourceCache::decrementRefcount(SkiaColorFilter* filterResource) { 141 SkSafeUnref(filterResource->getSkColorFilter()); 142 decrementRefcount((void*) filterResource); 143 } 144 145 void ResourceCache::decrementRefcount(Layer* layerResource) { 146 decrementRefcount((void*) layerResource); 147 } 148 149 void 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 162 void ResourceCache::decrementRefcountLocked(SkBitmap* bitmapResource) { 163 SkSafeUnref(bitmapResource->pixelRef()); 164 SkSafeUnref(bitmapResource->getColorTable()); 165 decrementRefcountLocked((void*) bitmapResource); 166 } 167 168 void ResourceCache::decrementRefcountLocked(SkPath* pathResource) { 169 decrementRefcountLocked((void*) pathResource); 170 } 171 172 void ResourceCache::decrementRefcountLocked(SkiaShader* shaderResource) { 173 SkSafeUnref(shaderResource->getSkShader()); 174 decrementRefcountLocked((void*) shaderResource); 175 } 176 177 void ResourceCache::decrementRefcountLocked(SkiaColorFilter* filterResource) { 178 SkSafeUnref(filterResource->getSkColorFilter()); 179 decrementRefcountLocked((void*) filterResource); 180 } 181 182 void ResourceCache::decrementRefcountLocked(Layer* layerResource) { 183 decrementRefcountLocked((void*) layerResource); 184 } 185 186 void ResourceCache::destructor(SkPath* resource) { 187 Mutex::Autolock _l(mLock); 188 destructorLocked(resource); 189 } 190 191 void 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 208 void ResourceCache::destructor(SkBitmap* resource) { 209 Mutex::Autolock _l(mLock); 210 destructorLocked(resource); 211 } 212 213 void 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 230 void ResourceCache::destructor(SkiaShader* resource) { 231 Mutex::Autolock _l(mLock); 232 destructorLocked(resource); 233 } 234 235 void 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 249 void ResourceCache::destructor(SkiaColorFilter* resource) { 250 Mutex::Autolock _l(mLock); 251 destructorLocked(resource); 252 } 253 254 void 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 */ 272 bool 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 */ 281 bool 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 */ 306 void 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