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(%zu): resource, ref = 0x%p, 0x%p",
     35                 i, mCache->keyAt(i), mCache->valueAt(i));
     36         ALOGD("  ResourceCache: mCache(%zu): 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<const 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(const SkBitmap* bitmapResource) {
     65     bitmapResource->pixelRef()->globalRef();
     66     SkSafeRef(bitmapResource->getColorTable());
     67     incrementRefcount((void*) bitmapResource, kBitmap);
     68 }
     69 
     70 void ResourceCache::incrementRefcount(const SkPath* pathResource) {
     71     incrementRefcount((void*) pathResource, kPath);
     72 }
     73 
     74 void ResourceCache::incrementRefcount(const Res_png_9patch* patchResource) {
     75     incrementRefcount((void*) patchResource, kNinePatch);
     76 }
     77 
     78 void ResourceCache::incrementRefcount(Layer* layerResource) {
     79     incrementRefcount((void*) layerResource, kLayer);
     80 }
     81 
     82 void ResourceCache::incrementRefcountLocked(void* resource, ResourceType resourceType) {
     83     ssize_t index = mCache->indexOfKey(resource);
     84     ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
     85     if (ref == NULL || mCache->size() == 0) {
     86         ref = new ResourceReference(resourceType);
     87         mCache->add(resource, ref);
     88     }
     89     ref->refCount++;
     90 }
     91 
     92 void ResourceCache::incrementRefcountLocked(const SkBitmap* bitmapResource) {
     93     bitmapResource->pixelRef()->globalRef();
     94     SkSafeRef(bitmapResource->getColorTable());
     95     incrementRefcountLocked((void*) bitmapResource, kBitmap);
     96 }
     97 
     98 void ResourceCache::incrementRefcountLocked(const SkPath* pathResource) {
     99     incrementRefcountLocked((void*) pathResource, kPath);
    100 }
    101 
    102 void ResourceCache::incrementRefcountLocked(const Res_png_9patch* patchResource) {
    103     incrementRefcountLocked((void*) patchResource, kNinePatch);
    104 }
    105 
    106 void ResourceCache::incrementRefcountLocked(Layer* layerResource) {
    107     incrementRefcountLocked((void*) layerResource, kLayer);
    108 }
    109 
    110 void ResourceCache::decrementRefcount(void* resource) {
    111     Mutex::Autolock _l(mLock);
    112     decrementRefcountLocked(resource);
    113 }
    114 
    115 void ResourceCache::decrementRefcount(const SkBitmap* bitmapResource) {
    116     bitmapResource->pixelRef()->globalUnref();
    117     SkSafeUnref(bitmapResource->getColorTable());
    118     decrementRefcount((void*) bitmapResource);
    119 }
    120 
    121 void ResourceCache::decrementRefcount(const SkPath* pathResource) {
    122     decrementRefcount((void*) pathResource);
    123 }
    124 
    125 void ResourceCache::decrementRefcount(const Res_png_9patch* patchResource) {
    126     decrementRefcount((void*) patchResource);
    127 }
    128 
    129 void ResourceCache::decrementRefcount(Layer* layerResource) {
    130     decrementRefcount((void*) layerResource);
    131 }
    132 
    133 void ResourceCache::decrementRefcountLocked(void* resource) {
    134     ssize_t index = mCache->indexOfKey(resource);
    135     ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
    136     if (ref == NULL) {
    137         // Should not get here - shouldn't get a call to decrement if we're not yet tracking it
    138         return;
    139     }
    140     ref->refCount--;
    141     if (ref->refCount == 0) {
    142         deleteResourceReferenceLocked(resource, ref);
    143     }
    144 }
    145 
    146 void ResourceCache::decrementRefcountLocked(const SkBitmap* bitmapResource) {
    147     bitmapResource->pixelRef()->globalUnref();
    148     SkSafeUnref(bitmapResource->getColorTable());
    149     decrementRefcountLocked((void*) bitmapResource);
    150 }
    151 
    152 void ResourceCache::decrementRefcountLocked(const SkPath* pathResource) {
    153     decrementRefcountLocked((void*) pathResource);
    154 }
    155 
    156 void ResourceCache::decrementRefcountLocked(const Res_png_9patch* patchResource) {
    157     decrementRefcountLocked((void*) patchResource);
    158 }
    159 
    160 void ResourceCache::decrementRefcountLocked(Layer* layerResource) {
    161     decrementRefcountLocked((void*) layerResource);
    162 }
    163 
    164 void ResourceCache::destructor(SkPath* resource) {
    165     Mutex::Autolock _l(mLock);
    166     destructorLocked(resource);
    167 }
    168 
    169 void ResourceCache::destructorLocked(SkPath* resource) {
    170     ssize_t index = mCache->indexOfKey(resource);
    171     ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
    172     if (ref == NULL) {
    173         // If we're not tracking this resource, just delete it
    174         if (Caches::hasInstance()) {
    175             Caches::getInstance().pathCache.removeDeferred(resource);
    176         } else {
    177             delete resource;
    178         }
    179         return;
    180     }
    181     ref->destroyed = true;
    182     if (ref->refCount == 0) {
    183         deleteResourceReferenceLocked(resource, ref);
    184     }
    185 }
    186 
    187 void ResourceCache::destructor(const SkBitmap* resource) {
    188     Mutex::Autolock _l(mLock);
    189     destructorLocked(resource);
    190 }
    191 
    192 void ResourceCache::destructorLocked(const SkBitmap* resource) {
    193     ssize_t index = mCache->indexOfKey(resource);
    194     ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
    195     if (ref == NULL) {
    196         // If we're not tracking this resource, just delete it
    197         if (Caches::hasInstance()) {
    198             Caches::getInstance().textureCache.removeDeferred(resource);
    199         } else {
    200             delete resource;
    201         }
    202         return;
    203     }
    204     ref->destroyed = true;
    205     if (ref->refCount == 0) {
    206         deleteResourceReferenceLocked(resource, ref);
    207     }
    208 }
    209 
    210 void ResourceCache::destructor(Res_png_9patch* resource) {
    211     Mutex::Autolock _l(mLock);
    212     destructorLocked(resource);
    213 }
    214 
    215 void ResourceCache::destructorLocked(Res_png_9patch* resource) {
    216     ssize_t index = mCache->indexOfKey(resource);
    217     ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
    218     if (ref == NULL) {
    219         // If we're not tracking this resource, just delete it
    220         if (Caches::hasInstance()) {
    221             Caches::getInstance().patchCache.removeDeferred(resource);
    222         } else {
    223             // A Res_png_9patch is actually an array of byte that's larger
    224             // than sizeof(Res_png_9patch). It must be freed as an array.
    225             delete[] (int8_t*) resource;
    226         }
    227         return;
    228     }
    229     ref->destroyed = true;
    230     if (ref->refCount == 0) {
    231         deleteResourceReferenceLocked(resource, ref);
    232     }
    233 }
    234 
    235 /**
    236  * Return value indicates whether resource was actually recycled, which happens when RefCnt
    237  * reaches 0.
    238  */
    239 bool ResourceCache::recycle(SkBitmap* resource) {
    240     Mutex::Autolock _l(mLock);
    241     return recycleLocked(resource);
    242 }
    243 
    244 /**
    245  * Return value indicates whether resource was actually recycled, which happens when RefCnt
    246  * reaches 0.
    247  */
    248 bool ResourceCache::recycleLocked(SkBitmap* resource) {
    249     ssize_t index = mCache->indexOfKey(resource);
    250     if (index < 0) {
    251         // not tracking this resource; just recycle the pixel data
    252         resource->setPixels(NULL, NULL);
    253         return true;
    254     }
    255     ResourceReference* ref = mCache->valueAt(index);
    256     if (ref == NULL) {
    257         // Should not get here - shouldn't get a call to recycle if we're not yet tracking it
    258         return true;
    259     }
    260     ref->recycled = true;
    261     if (ref->refCount == 0) {
    262         deleteResourceReferenceLocked(resource, ref);
    263         return true;
    264     }
    265     // Still referring to resource, don't recycle yet
    266     return false;
    267 }
    268 
    269 /**
    270  * This method should only be called while the mLock mutex is held (that mutex is grabbed
    271  * by the various destructor() and recycle() methods which call this method).
    272  */
    273 void ResourceCache::deleteResourceReferenceLocked(const void* resource, ResourceReference* ref) {
    274     if (ref->recycled && ref->resourceType == kBitmap) {
    275         ((SkBitmap*) resource)->setPixels(NULL, NULL);
    276     }
    277     if (ref->destroyed || ref->resourceType == kLayer) {
    278         switch (ref->resourceType) {
    279             case kBitmap: {
    280                 SkBitmap* bitmap = (SkBitmap*) resource;
    281                 if (Caches::hasInstance()) {
    282                     Caches::getInstance().textureCache.removeDeferred(bitmap);
    283                 } else {
    284                     delete bitmap;
    285                 }
    286             }
    287             break;
    288             case kPath: {
    289                 SkPath* path = (SkPath*) resource;
    290                 if (Caches::hasInstance()) {
    291                     Caches::getInstance().pathCache.removeDeferred(path);
    292                 } else {
    293                     delete path;
    294                 }
    295             }
    296             break;
    297             case kNinePatch: {
    298                 if (Caches::hasInstance()) {
    299                     Caches::getInstance().patchCache.removeDeferred((Res_png_9patch*) resource);
    300                 } else {
    301                     // A Res_png_9patch is actually an array of byte that's larger
    302                     // than sizeof(Res_png_9patch). It must be freed as an array.
    303                     int8_t* patch = (int8_t*) resource;
    304                     delete[] patch;
    305                 }
    306             }
    307             break;
    308             case kLayer: {
    309                 Layer* layer = (Layer*) resource;
    310                 Caches::getInstance().deleteLayerDeferred(layer);
    311             }
    312             break;
    313         }
    314     }
    315     mCache->removeItem(resource);
    316     delete ref;
    317 }
    318 
    319 }; // namespace uirenderer
    320 }; // namespace android
    321