ResourceCache.cpp revision d586ad9c9fec80aa1d24d6b53cd2c8d5b47fe868
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 LOGD("ResourceCache: cacheReport:"); 30 for (size_t i = 0; i < mCache->size(); ++i) { 31 ResourceReference* ref = mCache->valueAt(i); 32 LOGD(" ResourceCache: mCache(%d): resource, ref = 0x%p, 0x%p", 33 i, mCache->keyAt(i), mCache->valueAt(i)); 34 LOGD(" 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::incrementRefcount(void* resource, ResourceType resourceType) { 50 Mutex::Autolock _l(mLock); 51 ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL; 52 if (ref == NULL || mCache->size() == 0) { 53 ref = new ResourceReference(resourceType); 54 mCache->add(resource, ref); 55 } 56 ref->refCount++; 57} 58 59void ResourceCache::incrementRefcount(SkBitmap* bitmapResource) { 60 SkSafeRef(bitmapResource->pixelRef()); 61 SkSafeRef(bitmapResource->getColorTable()); 62 incrementRefcount((void*)bitmapResource, kBitmap); 63} 64 65void ResourceCache::incrementRefcount(SkPath* pathResource) { 66 incrementRefcount((void*)pathResource, kPath); 67} 68 69void ResourceCache::incrementRefcount(SkiaShader* shaderResource) { 70 SkSafeRef(shaderResource->getSkShader()); 71 incrementRefcount((void*) shaderResource, kShader); 72} 73 74void ResourceCache::incrementRefcount(SkiaColorFilter* filterResource) { 75 SkSafeRef(filterResource->getSkColorFilter()); 76 incrementRefcount((void*) filterResource, kColorFilter); 77} 78 79void ResourceCache::decrementRefcount(void* resource) { 80 Mutex::Autolock _l(mLock); 81 ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL; 82 if (ref == NULL) { 83 // Should not get here - shouldn't get a call to decrement if we're not yet tracking it 84 return; 85 } 86 ref->refCount--; 87 if (ref->refCount == 0) { 88 deleteResourceReference(resource, ref); 89 } 90} 91 92void ResourceCache::decrementRefcount(SkBitmap* bitmapResource) { 93 SkSafeUnref(bitmapResource->pixelRef()); 94 SkSafeUnref(bitmapResource->getColorTable()); 95 decrementRefcount((void*) bitmapResource); 96} 97 98void ResourceCache::decrementRefcount(SkPath* pathResource) { 99 decrementRefcount((void*) pathResource); 100} 101 102void ResourceCache::decrementRefcount(SkiaShader* shaderResource) { 103 SkSafeUnref(shaderResource->getSkShader()); 104 decrementRefcount((void*) shaderResource); 105} 106 107void ResourceCache::decrementRefcount(SkiaColorFilter* filterResource) { 108 SkSafeUnref(filterResource->getSkColorFilter()); 109 decrementRefcount((void*) filterResource); 110} 111 112void ResourceCache::recycle(SkBitmap* resource) { 113 Mutex::Autolock _l(mLock); 114 if (mCache->indexOfKey(resource) < 0) { 115 // not tracking this resource; just recycle the pixel data 116 resource->setPixels(NULL, NULL); 117 return; 118 } 119 ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL; 120 if (ref == NULL) { 121 // Should not get here - shouldn't get a call to recycle if we're not yet tracking it 122 return; 123 } 124 ref->recycled = true; 125 if (ref->refCount == 0) { 126 deleteResourceReference(resource, ref); 127 } 128} 129 130void ResourceCache::destructor(SkPath* resource) { 131 Mutex::Autolock _l(mLock); 132 ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL; 133 if (ref == NULL) { 134 // If we're not tracking this resource, just delete it 135 if (Caches::hasInstance()) { 136 Caches::getInstance().pathCache.removeDeferred(resource); 137 } 138 delete resource; 139 return; 140 } 141 ref->destroyed = true; 142 if (ref->refCount == 0) { 143 deleteResourceReference(resource, ref); 144 } 145} 146 147void ResourceCache::destructor(SkBitmap* resource) { 148 Mutex::Autolock _l(mLock); 149 ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL; 150 if (ref == NULL) { 151 // If we're not tracking this resource, just delete it 152 if (Caches::hasInstance()) { 153 Caches::getInstance().textureCache.removeDeferred(resource); 154 } 155 delete resource; 156 return; 157 } 158 ref->destroyed = true; 159 if (ref->refCount == 0) { 160 deleteResourceReference(resource, ref); 161 } 162} 163 164void ResourceCache::destructor(SkiaShader* resource) { 165 Mutex::Autolock _l(mLock); 166 ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL; 167 if (ref == NULL) { 168 // If we're not tracking this resource, just delete it 169 if (Caches::hasInstance()) { 170 Caches::getInstance().gradientCache.removeDeferred(resource->getSkShader()); 171 } 172 delete resource; 173 return; 174 } 175 ref->destroyed = true; 176 if (ref->refCount == 0) { 177 deleteResourceReference(resource, ref); 178 } 179} 180 181void ResourceCache::destructor(SkiaColorFilter* resource) { 182 Mutex::Autolock _l(mLock); 183 ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL; 184 if (ref == NULL) { 185 // If we're not tracking this resource, just delete it 186 delete resource; 187 return; 188 } 189 ref->destroyed = true; 190 if (ref->refCount == 0) { 191 deleteResourceReference(resource, ref); 192 } 193} 194 195/** 196 * This method should only be called while the mLock mutex is held (that mutex is grabbed 197 * by the various destructor() and recycle() methods which call this method). 198 */ 199void ResourceCache::deleteResourceReference(void* resource, ResourceReference* ref) { 200 if (ref->recycled && ref->resourceType == kBitmap) { 201 ((SkBitmap*) resource)->setPixels(NULL, NULL); 202 } 203 if (ref->destroyed) { 204 switch (ref->resourceType) { 205 case kBitmap: { 206 SkBitmap* bitmap = (SkBitmap*) resource; 207 if (Caches::hasInstance()) { 208 Caches::getInstance().textureCache.removeDeferred(bitmap); 209 } 210 delete bitmap; 211 } 212 break; 213 case kPath: { 214 SkPath* path = (SkPath*) resource; 215 if (Caches::hasInstance()) { 216 Caches::getInstance().pathCache.removeDeferred(path); 217 } 218 delete path; 219 } 220 break; 221 case kShader: { 222 SkiaShader* shader = (SkiaShader*) resource; 223 if (Caches::hasInstance()) { 224 Caches::getInstance().gradientCache.removeDeferred(shader->getSkShader()); 225 } 226 delete shader; 227 } 228 break; 229 case kColorFilter: { 230 SkiaColorFilter* filter = (SkiaColorFilter*) resource; 231 delete filter; 232 } 233 break; 234 } 235 } 236 mCache->removeItem(resource); 237 delete ref; 238} 239 240}; // namespace uirenderer 241}; // namespace android 242