Home | History | Annotate | Download | only in hwui
      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::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 
     59 void ResourceCache::incrementRefcount(SkBitmap* bitmapResource) {
     60     SkSafeRef(bitmapResource->pixelRef());
     61     SkSafeRef(bitmapResource->getColorTable());
     62     incrementRefcount((void*) bitmapResource, kBitmap);
     63 }
     64 
     65 void ResourceCache::incrementRefcount(SkPath* pathResource) {
     66     incrementRefcount((void*) pathResource, kPath);
     67 }
     68 
     69 void ResourceCache::incrementRefcount(SkiaShader* shaderResource) {
     70     SkSafeRef(shaderResource->getSkShader());
     71     incrementRefcount((void*) shaderResource, kShader);
     72 }
     73 
     74 void ResourceCache::incrementRefcount(SkiaColorFilter* filterResource) {
     75     SkSafeRef(filterResource->getSkColorFilter());
     76     incrementRefcount((void*) filterResource, kColorFilter);
     77 }
     78 
     79 void 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 
     92 void ResourceCache::decrementRefcount(SkBitmap* bitmapResource) {
     93     SkSafeUnref(bitmapResource->pixelRef());
     94     SkSafeUnref(bitmapResource->getColorTable());
     95     decrementRefcount((void*) bitmapResource);
     96 }
     97 
     98 void ResourceCache::decrementRefcount(SkPath* pathResource) {
     99     decrementRefcount((void*) pathResource);
    100 }
    101 
    102 void ResourceCache::decrementRefcount(SkiaShader* shaderResource) {
    103     SkSafeUnref(shaderResource->getSkShader());
    104     decrementRefcount((void*) shaderResource);
    105 }
    106 
    107 void ResourceCache::decrementRefcount(SkiaColorFilter* filterResource) {
    108     SkSafeUnref(filterResource->getSkColorFilter());
    109     decrementRefcount((void*) filterResource);
    110 }
    111 
    112 void 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 
    130 void 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 
    147 void 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 
    164 void 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         delete resource;
    170         return;
    171     }
    172     ref->destroyed = true;
    173     if (ref->refCount == 0) {
    174         deleteResourceReference(resource, ref);
    175     }
    176 }
    177 
    178 void ResourceCache::destructor(SkiaColorFilter* resource) {
    179     Mutex::Autolock _l(mLock);
    180     ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL;
    181     if (ref == NULL) {
    182         // If we're not tracking this resource, just delete it
    183         delete resource;
    184         return;
    185     }
    186     ref->destroyed = true;
    187     if (ref->refCount == 0) {
    188         deleteResourceReference(resource, ref);
    189     }
    190 }
    191 
    192 /**
    193  * This method should only be called while the mLock mutex is held (that mutex is grabbed
    194  * by the various destructor() and recycle() methods which call this method).
    195  */
    196 void ResourceCache::deleteResourceReference(void* resource, ResourceReference* ref) {
    197     if (ref->recycled && ref->resourceType == kBitmap) {
    198         ((SkBitmap*) resource)->setPixels(NULL, NULL);
    199     }
    200     if (ref->destroyed) {
    201         switch (ref->resourceType) {
    202             case kBitmap: {
    203                 SkBitmap* bitmap = (SkBitmap*) resource;
    204                 if (Caches::hasInstance()) {
    205                     Caches::getInstance().textureCache.removeDeferred(bitmap);
    206                 }
    207                 delete bitmap;
    208             }
    209             break;
    210             case kPath: {
    211                 SkPath* path = (SkPath*) resource;
    212                 if (Caches::hasInstance()) {
    213                     Caches::getInstance().pathCache.removeDeferred(path);
    214                 }
    215                 delete path;
    216             }
    217             break;
    218             case kShader: {
    219                 SkiaShader* shader = (SkiaShader*) resource;
    220                 delete shader;
    221             }
    222             break;
    223             case kColorFilter: {
    224                 SkiaColorFilter* filter = (SkiaColorFilter*) resource;
    225                 delete filter;
    226             }
    227             break;
    228         }
    229     }
    230     mCache->removeItem(resource);
    231     delete ref;
    232 }
    233 
    234 }; // namespace uirenderer
    235 }; // namespace android
    236