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 #define LOG_TAG "OpenGLRenderer"
     18 
     19 #include <SkPixelRef.h>
     20 #include "ResourceCache.h"
     21 #include "Caches.h"
     22 
     23 namespace android {
     24 namespace uirenderer {
     25 
     26 ///////////////////////////////////////////////////////////////////////////////
     27 // Resource cache
     28 ///////////////////////////////////////////////////////////////////////////////
     29 
     30 void ResourceCache::logCache() {
     31     ALOGD("ResourceCache: cacheReport:");
     32     for (size_t i = 0; i < mCache->size(); ++i) {
     33         ResourceReference* ref = mCache->valueAt(i);
     34         ALOGD("  ResourceCache: mCache(%d): resource, ref = 0x%p, 0x%p",
     35                 i, mCache->keyAt(i), mCache->valueAt(i));
     36         ALOGD("  ResourceCache: mCache(%d): refCount, recycled, destroyed, type = %d, %d, %d, %d",
     37                 i, ref->refCount, ref->recycled, ref->destroyed, ref->resourceType);
     38     }
     39 }
     40 
     41 ResourceCache::ResourceCache() {
     42     Mutex::Autolock _l(mLock);
     43     mCache = new KeyedVector<void*, ResourceReference*>();
     44 }
     45 
     46 ResourceCache::~ResourceCache() {
     47     Mutex::Autolock _l(mLock);
     48     delete mCache;
     49 }
     50 
     51 void ResourceCache::lock() {
     52     mLock.lock();
     53 }
     54 
     55 void ResourceCache::unlock() {
     56     mLock.unlock();
     57 }
     58 
     59 void ResourceCache::incrementRefcount(void* resource, ResourceType resourceType) {
     60     Mutex::Autolock _l(mLock);
     61     incrementRefcountLocked(resource, resourceType);
     62 }
     63 
     64 void ResourceCache::incrementRefcount(SkBitmap* bitmapResource) {
     65     bitmapResource->pixelRef()->globalRef();
     66     SkSafeRef(bitmapResource->getColorTable());
     67     incrementRefcount((void*) bitmapResource, kBitmap);
     68 }
     69 
     70 void ResourceCache::incrementRefcount(SkPath* pathResource) {
     71     incrementRefcount((void*) pathResource, kPath);
     72 }
     73 
     74 void ResourceCache::incrementRefcount(SkiaShader* shaderResource) {
     75     SkSafeRef(shaderResource->getSkShader());
     76     incrementRefcount((void*) shaderResource, kShader);
     77 }
     78 
     79 void ResourceCache::incrementRefcount(SkiaColorFilter* filterResource) {
     80     SkSafeRef(filterResource->getSkColorFilter());
     81     incrementRefcount((void*) filterResource, kColorFilter);
     82 }
     83 
     84 void ResourceCache::incrementRefcount(Res_png_9patch* patchResource) {
     85     incrementRefcount((void*) patchResource, kNinePatch);
     86 }
     87 
     88 void ResourceCache::incrementRefcount(Layer* layerResource) {
     89     incrementRefcount((void*) layerResource, kLayer);
     90 }
     91 
     92 void ResourceCache::incrementRefcountLocked(void* resource, ResourceType resourceType) {
     93     ssize_t index = mCache->indexOfKey(resource);
     94     ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
     95     if (ref == NULL || mCache->size() == 0) {
     96         ref = new ResourceReference(resourceType);
     97         mCache->add(resource, ref);
     98     }
     99     ref->refCount++;
    100 }
    101 
    102 void ResourceCache::incrementRefcountLocked(SkBitmap* bitmapResource) {
    103     bitmapResource->pixelRef()->globalRef();
    104     SkSafeRef(bitmapResource->getColorTable());
    105     incrementRefcountLocked((void*) bitmapResource, kBitmap);
    106 }
    107 
    108 void ResourceCache::incrementRefcountLocked(SkPath* pathResource) {
    109     incrementRefcountLocked((void*) pathResource, kPath);
    110 }
    111 
    112 void ResourceCache::incrementRefcountLocked(SkiaShader* shaderResource) {
    113     SkSafeRef(shaderResource->getSkShader());
    114     incrementRefcountLocked((void*) shaderResource, kShader);
    115 }
    116 
    117 void ResourceCache::incrementRefcountLocked(SkiaColorFilter* filterResource) {
    118     SkSafeRef(filterResource->getSkColorFilter());
    119     incrementRefcountLocked((void*) filterResource, kColorFilter);
    120 }
    121 
    122 void ResourceCache::incrementRefcountLocked(Res_png_9patch* patchResource) {
    123     incrementRefcountLocked((void*) patchResource, kNinePatch);
    124 }
    125 
    126 void ResourceCache::incrementRefcountLocked(Layer* layerResource) {
    127     incrementRefcountLocked((void*) layerResource, kLayer);
    128 }
    129 
    130 void ResourceCache::decrementRefcount(void* resource) {
    131     Mutex::Autolock _l(mLock);
    132     decrementRefcountLocked(resource);
    133 }
    134 
    135 void ResourceCache::decrementRefcount(SkBitmap* bitmapResource) {
    136     bitmapResource->pixelRef()->globalUnref();
    137     SkSafeUnref(bitmapResource->getColorTable());
    138     decrementRefcount((void*) bitmapResource);
    139 }
    140 
    141 void ResourceCache::decrementRefcount(SkPath* pathResource) {
    142     decrementRefcount((void*) pathResource);
    143 }
    144 
    145 void ResourceCache::decrementRefcount(SkiaShader* shaderResource) {
    146     SkSafeUnref(shaderResource->getSkShader());
    147     decrementRefcount((void*) shaderResource);
    148 }
    149 
    150 void ResourceCache::decrementRefcount(SkiaColorFilter* filterResource) {
    151     SkSafeUnref(filterResource->getSkColorFilter());
    152     decrementRefcount((void*) filterResource);
    153 }
    154 
    155 void ResourceCache::decrementRefcount(Res_png_9patch* patchResource) {
    156     decrementRefcount((void*) patchResource);
    157 }
    158 
    159 void ResourceCache::decrementRefcount(Layer* layerResource) {
    160     decrementRefcount((void*) layerResource);
    161 }
    162 
    163 void ResourceCache::decrementRefcountLocked(void* resource) {
    164     ssize_t index = mCache->indexOfKey(resource);
    165     ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
    166     if (ref == NULL) {
    167         // Should not get here - shouldn't get a call to decrement if we're not yet tracking it
    168         return;
    169     }
    170     ref->refCount--;
    171     if (ref->refCount == 0) {
    172         deleteResourceReferenceLocked(resource, ref);
    173     }
    174 }
    175 
    176 void ResourceCache::decrementRefcountLocked(SkBitmap* bitmapResource) {
    177     bitmapResource->pixelRef()->globalUnref();
    178     SkSafeUnref(bitmapResource->getColorTable());
    179     decrementRefcountLocked((void*) bitmapResource);
    180 }
    181 
    182 void ResourceCache::decrementRefcountLocked(SkPath* pathResource) {
    183     decrementRefcountLocked((void*) pathResource);
    184 }
    185 
    186 void ResourceCache::decrementRefcountLocked(SkiaShader* shaderResource) {
    187     SkSafeUnref(shaderResource->getSkShader());
    188     decrementRefcountLocked((void*) shaderResource);
    189 }
    190 
    191 void ResourceCache::decrementRefcountLocked(SkiaColorFilter* filterResource) {
    192     SkSafeUnref(filterResource->getSkColorFilter());
    193     decrementRefcountLocked((void*) filterResource);
    194 }
    195 
    196 void ResourceCache::decrementRefcountLocked(Res_png_9patch* patchResource) {
    197     decrementRefcountLocked((void*) patchResource);
    198 }
    199 
    200 void ResourceCache::decrementRefcountLocked(Layer* layerResource) {
    201     decrementRefcountLocked((void*) layerResource);
    202 }
    203 
    204 void ResourceCache::destructor(SkPath* resource) {
    205     Mutex::Autolock _l(mLock);
    206     destructorLocked(resource);
    207 }
    208 
    209 void ResourceCache::destructorLocked(SkPath* resource) {
    210     ssize_t index = mCache->indexOfKey(resource);
    211     ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
    212     if (ref == NULL) {
    213         // If we're not tracking this resource, just delete it
    214         if (Caches::hasInstance()) {
    215             Caches::getInstance().pathCache.removeDeferred(resource);
    216         }
    217         delete resource;
    218         return;
    219     }
    220     ref->destroyed = true;
    221     if (ref->refCount == 0) {
    222         deleteResourceReferenceLocked(resource, ref);
    223     }
    224 }
    225 
    226 void ResourceCache::destructor(SkBitmap* resource) {
    227     Mutex::Autolock _l(mLock);
    228     destructorLocked(resource);
    229 }
    230 
    231 void ResourceCache::destructorLocked(SkBitmap* resource) {
    232     ssize_t index = mCache->indexOfKey(resource);
    233     ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
    234     if (ref == NULL) {
    235         // If we're not tracking this resource, just delete it
    236         if (Caches::hasInstance()) {
    237             Caches::getInstance().textureCache.removeDeferred(resource);
    238         }
    239         delete resource;
    240         return;
    241     }
    242     ref->destroyed = true;
    243     if (ref->refCount == 0) {
    244         deleteResourceReferenceLocked(resource, ref);
    245     }
    246 }
    247 
    248 void ResourceCache::destructor(SkiaShader* resource) {
    249     Mutex::Autolock _l(mLock);
    250     destructorLocked(resource);
    251 }
    252 
    253 void ResourceCache::destructorLocked(SkiaShader* resource) {
    254     ssize_t index = mCache->indexOfKey(resource);
    255     ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
    256     if (ref == NULL) {
    257         // If we're not tracking this resource, just delete it
    258         delete resource;
    259         return;
    260     }
    261     ref->destroyed = true;
    262     if (ref->refCount == 0) {
    263         deleteResourceReferenceLocked(resource, ref);
    264     }
    265 }
    266 
    267 void ResourceCache::destructor(SkiaColorFilter* resource) {
    268     Mutex::Autolock _l(mLock);
    269     destructorLocked(resource);
    270 }
    271 
    272 void ResourceCache::destructorLocked(SkiaColorFilter* resource) {
    273     ssize_t index = mCache->indexOfKey(resource);
    274     ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
    275     if (ref == NULL) {
    276         // If we're not tracking this resource, just delete it
    277         delete resource;
    278         return;
    279     }
    280     ref->destroyed = true;
    281     if (ref->refCount == 0) {
    282         deleteResourceReferenceLocked(resource, ref);
    283     }
    284 }
    285 
    286 void ResourceCache::destructor(Res_png_9patch* resource) {
    287     Mutex::Autolock _l(mLock);
    288     destructorLocked(resource);
    289 }
    290 
    291 void ResourceCache::destructorLocked(Res_png_9patch* resource) {
    292     ssize_t index = mCache->indexOfKey(resource);
    293     ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
    294     if (ref == NULL) {
    295         if (Caches::hasInstance()) {
    296             Caches::getInstance().patchCache.removeDeferred(resource);
    297         }
    298         // If we're not tracking this resource, just delete it
    299         // A Res_png_9patch is actually an array of byte that's larger
    300         // than sizeof(Res_png_9patch). It must be freed as an array.
    301         delete[] (int8_t*) resource;
    302         return;
    303     }
    304     ref->destroyed = true;
    305     if (ref->refCount == 0) {
    306         deleteResourceReferenceLocked(resource, ref);
    307     }
    308 }
    309 
    310 /**
    311  * Return value indicates whether resource was actually recycled, which happens when RefCnt
    312  * reaches 0.
    313  */
    314 bool ResourceCache::recycle(SkBitmap* resource) {
    315     Mutex::Autolock _l(mLock);
    316     return recycleLocked(resource);
    317 }
    318 
    319 /**
    320  * Return value indicates whether resource was actually recycled, which happens when RefCnt
    321  * reaches 0.
    322  */
    323 bool ResourceCache::recycleLocked(SkBitmap* resource) {
    324     ssize_t index = mCache->indexOfKey(resource);
    325     if (index < 0) {
    326         // not tracking this resource; just recycle the pixel data
    327         resource->setPixels(NULL, NULL);
    328         return true;
    329     }
    330     ResourceReference* ref = mCache->valueAt(index);
    331     if (ref == NULL) {
    332         // Should not get here - shouldn't get a call to recycle if we're not yet tracking it
    333         return true;
    334     }
    335     ref->recycled = true;
    336     if (ref->refCount == 0) {
    337         deleteResourceReferenceLocked(resource, ref);
    338         return true;
    339     }
    340     // Still referring to resource, don't recycle yet
    341     return false;
    342 }
    343 
    344 /**
    345  * This method should only be called while the mLock mutex is held (that mutex is grabbed
    346  * by the various destructor() and recycle() methods which call this method).
    347  */
    348 void ResourceCache::deleteResourceReferenceLocked(void* resource, ResourceReference* ref) {
    349     if (ref->recycled && ref->resourceType == kBitmap) {
    350         ((SkBitmap*) resource)->setPixels(NULL, NULL);
    351     }
    352     if (ref->destroyed || ref->resourceType == kLayer) {
    353         switch (ref->resourceType) {
    354             case kBitmap: {
    355                 SkBitmap* bitmap = (SkBitmap*) resource;
    356                 if (Caches::hasInstance()) {
    357                     Caches::getInstance().textureCache.removeDeferred(bitmap);
    358                 }
    359                 delete bitmap;
    360             }
    361             break;
    362             case kPath: {
    363                 SkPath* path = (SkPath*) resource;
    364                 if (Caches::hasInstance()) {
    365                     Caches::getInstance().pathCache.removeDeferred(path);
    366                 }
    367                 delete path;
    368             }
    369             break;
    370             case kShader: {
    371                 SkiaShader* shader = (SkiaShader*) resource;
    372                 delete shader;
    373             }
    374             break;
    375             case kColorFilter: {
    376                 SkiaColorFilter* filter = (SkiaColorFilter*) resource;
    377                 delete filter;
    378             }
    379             break;
    380             case kNinePatch: {
    381                 if (Caches::hasInstance()) {
    382                     Caches::getInstance().patchCache.removeDeferred((Res_png_9patch*) resource);
    383                 }
    384                 // A Res_png_9patch is actually an array of byte that's larger
    385                 // than sizeof(Res_png_9patch). It must be freed as an array.
    386                 int8_t* patch = (int8_t*) resource;
    387                 delete[] patch;
    388             }
    389             break;
    390             case kLayer: {
    391                 Layer* layer = (Layer*) resource;
    392                 Caches::getInstance().deleteLayerDeferred(layer);
    393             }
    394             break;
    395         }
    396     }
    397     mCache->removeItem(resource);
    398     delete ref;
    399 }
    400 
    401 }; // namespace uirenderer
    402 }; // namespace android
    403