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