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