diff options
Diffstat (limited to 'libs/hwui/ResourceCache.cpp')
-rw-r--r-- | libs/hwui/ResourceCache.cpp | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp new file mode 100644 index 0000000..5ebd2c0 --- /dev/null +++ b/libs/hwui/ResourceCache.cpp @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <SkPixelRef.h> +#include "ResourceCache.h" +#include "Caches.h" + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Resource cache +/////////////////////////////////////////////////////////////////////////////// + +void ResourceCache::logCache() { + LOGD("ResourceCache: cacheReport:"); + for (size_t i = 0; i < mCache->size(); ++i) { + ResourceReference* ref = mCache->valueAt(i); + LOGD(" ResourceCache: mCache(%d): resource, ref = 0x%p, 0x%p", + i, mCache->keyAt(i), mCache->valueAt(i)); + LOGD(" ResourceCache: mCache(%d): refCount, recycled, destroyed, type = %d, %d, %d, %d", + i, ref->refCount, ref->recycled, ref->destroyed, ref->resourceType); + } +} + +ResourceCache::ResourceCache() { + Mutex::Autolock _l(mLock); + mCache = new KeyedVector<void *, ResourceReference *>(); +} + +ResourceCache::~ResourceCache() { + Mutex::Autolock _l(mLock); + delete mCache; +} + +void ResourceCache::incrementRefcount(void* resource, ResourceType resourceType) { + Mutex::Autolock _l(mLock); + for (size_t i = 0; i < mCache->size(); ++i) { + void* ref = mCache->valueAt(i); + } + ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL; + if (ref == NULL || mCache->size() == 0) { + ref = new ResourceReference(resourceType); + mCache->add(resource, ref); + } + ref->refCount++; +} + +void ResourceCache::incrementRefcount(SkBitmap* bitmapResource) { + bitmapResource->pixelRef()->safeRef(); + bitmapResource->getColorTable()->safeRef(); + incrementRefcount((void*)bitmapResource, kBitmap); +} + +void ResourceCache::incrementRefcount(SkiaShader* shaderResource) { + shaderResource->getSkShader()->safeRef(); + incrementRefcount((void*)shaderResource, kShader); +} + +void ResourceCache::incrementRefcount(SkiaColorFilter* filterResource) { + filterResource->getSkColorFilter()->safeRef(); + incrementRefcount((void*)filterResource, kColorFilter); +} + +void ResourceCache::decrementRefcount(void* resource) { + Mutex::Autolock _l(mLock); + ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL; + if (ref == NULL) { + // Should not get here - shouldn't get a call to decrement if we're not yet tracking it + return; + } + ref->refCount--; + if (ref->refCount == 0) { + deleteResourceReference(resource, ref); + } +} + +void ResourceCache::decrementRefcount(SkBitmap* bitmapResource) { + bitmapResource->pixelRef()->safeUnref(); + bitmapResource->getColorTable()->safeUnref(); + decrementRefcount((void*)bitmapResource); +} + +void ResourceCache::decrementRefcount(SkiaShader* shaderResource) { + shaderResource->getSkShader()->safeUnref(); + decrementRefcount((void*)shaderResource); +} + +void ResourceCache::decrementRefcount(SkiaColorFilter* filterResource) { + filterResource->getSkColorFilter()->safeUnref(); + decrementRefcount((void*)filterResource); +} + +void ResourceCache::recycle(SkBitmap* resource) { + Mutex::Autolock _l(mLock); + if (mCache->indexOfKey(resource) < 0) { + // not tracking this resource; just recycle the pixel data + resource->setPixels(NULL, NULL); + return; + } + recycle((void*) resource); +} + +void ResourceCache::recycle(void* resource) { + Mutex::Autolock _l(mLock); + ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL; + if (ref == NULL) { + // Should not get here - shouldn't get a call to recycle if we're not yet tracking it + return; + } + ref->recycled = true; + if (ref->refCount == 0) { + deleteResourceReference(resource, ref); + } +} + +void ResourceCache::destructor(SkBitmap* resource) { + Mutex::Autolock _l(mLock); + ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL; + if (ref == NULL) { + // If we're not tracking this resource, just delete it + if (Caches::hasInstance()) { + Caches::getInstance().textureCache.removeDeferred(resource); + } + delete resource; + return; + } + ref->destroyed = true; + if (ref->refCount == 0) { + deleteResourceReference(resource, ref); + return; + } +} + +void ResourceCache::destructor(SkiaShader* resource) { + Mutex::Autolock _l(mLock); + ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL; + if (ref == NULL) { + // If we're not tracking this resource, just delete it + if (Caches::hasInstance()) { + Caches::getInstance().gradientCache.removeDeferred(resource->getSkShader()); + } + delete resource; + return; + } + ref->destroyed = true; + if (ref->refCount == 0) { + deleteResourceReference(resource, ref); + return; + } +} + +void ResourceCache::destructor(SkiaColorFilter* resource) { + Mutex::Autolock _l(mLock); + ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL; + if (ref == NULL) { + // If we're not tracking this resource, just delete it + delete resource; + return; + } + ref->destroyed = true; + if (ref->refCount == 0) { + deleteResourceReference(resource, ref); + return; + } +} + +/** + * This method should only be called while the mLock mutex is held (that mutex is grabbed + * by the various destructor() and recycle() methods which call this method). + */ +void ResourceCache::deleteResourceReference(void* resource, ResourceReference* ref) { + if (ref->recycled && ref->resourceType == kBitmap) { + ((SkBitmap*) resource)->setPixels(NULL, NULL); + } + if (ref->destroyed) { + switch (ref->resourceType) { + case kBitmap: + { + SkBitmap* bitmap = (SkBitmap*)resource; + if (Caches::hasInstance()) { + Caches::getInstance().textureCache.removeDeferred(bitmap); + } + delete bitmap; + } + break; + case kShader: + { + SkiaShader* shader = (SkiaShader*)resource; + if (Caches::hasInstance()) { + Caches::getInstance().gradientCache.removeDeferred(shader->getSkShader()); + } + delete shader; + } + break; + case kColorFilter: + { + SkiaColorFilter* filter = (SkiaColorFilter*)resource; + delete filter; + } + break; + } + } + mCache->removeItem(resource); + delete ref; +} + +}; // namespace uirenderer +}; // namespace android |