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 
     25 #ifdef USE_OPENGL_RENDERER
     26 using namespace uirenderer;
     27 ANDROID_SINGLETON_STATIC_INSTANCE(ResourceCache);
     28 #endif
     29 
     30 namespace uirenderer {
     31 
     32 ///////////////////////////////////////////////////////////////////////////////
     33 // Resource cache
     34 ///////////////////////////////////////////////////////////////////////////////
     35 
     36 void ResourceCache::logCache() {
     37     ALOGD("ResourceCache: cacheReport:");
     38     for (size_t i = 0; i < mCache->size(); ++i) {
     39         ResourceReference* ref = mCache->valueAt(i);
     40         ALOGD("  ResourceCache: mCache(%zu): resource, ref = 0x%p, 0x%p",
     41                 i, mCache->keyAt(i), mCache->valueAt(i));
     42         ALOGD("  ResourceCache: mCache(%zu): refCount, recycled, destroyed, type = %d, %d, %d, %d",
     43                 i, ref->refCount, ref->recycled, ref->destroyed, ref->resourceType);
     44     }
     45 }
     46 
     47 ResourceCache::ResourceCache() {
     48     Mutex::Autolock _l(mLock);
     49     mCache = new KeyedVector<const void*, ResourceReference*>();
     50 }
     51 
     52 ResourceCache::~ResourceCache() {
     53     Mutex::Autolock _l(mLock);
     54     delete mCache;
     55 }
     56 
     57 void ResourceCache::lock() {
     58     mLock.lock();
     59 }
     60 
     61 void ResourceCache::unlock() {
     62     mLock.unlock();
     63 }
     64 
     65 void ResourceCache::incrementRefcount(void* resource, ResourceType resourceType) {
     66     Mutex::Autolock _l(mLock);
     67     incrementRefcountLocked(resource, resourceType);
     68 }
     69 
     70 void ResourceCache::incrementRefcount(const SkBitmap* bitmapResource) {
     71     incrementRefcount((void*) bitmapResource, kBitmap);
     72 }
     73 
     74 void ResourceCache::incrementRefcount(const SkPath* pathResource) {
     75     incrementRefcount((void*) pathResource, kPath);
     76 }
     77 
     78 void ResourceCache::incrementRefcount(const Res_png_9patch* patchResource) {
     79     incrementRefcount((void*) patchResource, kNinePatch);
     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     incrementRefcountLocked((void*) bitmapResource, kBitmap);
     94 }
     95 
     96 void ResourceCache::incrementRefcountLocked(const SkPath* pathResource) {
     97     incrementRefcountLocked((void*) pathResource, kPath);
     98 }
     99 
    100 void ResourceCache::incrementRefcountLocked(const Res_png_9patch* patchResource) {
    101     incrementRefcountLocked((void*) patchResource, kNinePatch);
    102 }
    103 
    104 void ResourceCache::decrementRefcount(void* resource) {
    105     Mutex::Autolock _l(mLock);
    106     decrementRefcountLocked(resource);
    107 }
    108 
    109 void ResourceCache::decrementRefcount(const SkBitmap* bitmapResource) {
    110     decrementRefcount((void*) bitmapResource);
    111 }
    112 
    113 void ResourceCache::decrementRefcount(const SkPath* pathResource) {
    114     decrementRefcount((void*) pathResource);
    115 }
    116 
    117 void ResourceCache::decrementRefcount(const Res_png_9patch* patchResource) {
    118     decrementRefcount((void*) patchResource);
    119 }
    120 
    121 void ResourceCache::decrementRefcountLocked(void* resource) {
    122     ssize_t index = mCache->indexOfKey(resource);
    123     ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
    124     if (ref == NULL) {
    125         // Should not get here - shouldn't get a call to decrement if we're not yet tracking it
    126         return;
    127     }
    128     ref->refCount--;
    129     if (ref->refCount == 0) {
    130         deleteResourceReferenceLocked(resource, ref);
    131     }
    132 }
    133 
    134 void ResourceCache::decrementRefcountLocked(const SkBitmap* bitmapResource) {
    135     decrementRefcountLocked((void*) bitmapResource);
    136 }
    137 
    138 void ResourceCache::decrementRefcountLocked(const SkPath* pathResource) {
    139     decrementRefcountLocked((void*) pathResource);
    140 }
    141 
    142 void ResourceCache::decrementRefcountLocked(const Res_png_9patch* patchResource) {
    143     decrementRefcountLocked((void*) patchResource);
    144 }
    145 
    146 void ResourceCache::destructor(SkPath* resource) {
    147     Mutex::Autolock _l(mLock);
    148     destructorLocked(resource);
    149 }
    150 
    151 void ResourceCache::destructorLocked(SkPath* resource) {
    152     ssize_t index = mCache->indexOfKey(resource);
    153     ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
    154     if (ref == NULL) {
    155         // If we're not tracking this resource, just delete it
    156         if (Caches::hasInstance()) {
    157             Caches::getInstance().pathCache.removeDeferred(resource);
    158         } else {
    159             delete resource;
    160         }
    161         return;
    162     }
    163     ref->destroyed = true;
    164     if (ref->refCount == 0) {
    165         deleteResourceReferenceLocked(resource, ref);
    166     }
    167 }
    168 
    169 void ResourceCache::destructor(const SkBitmap* resource) {
    170     Mutex::Autolock _l(mLock);
    171     destructorLocked(resource);
    172 }
    173 
    174 void ResourceCache::destructorLocked(const SkBitmap* resource) {
    175     ssize_t index = mCache->indexOfKey(resource);
    176     ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
    177     if (ref == NULL) {
    178         // If we're not tracking this resource, just delete it
    179         if (Caches::hasInstance()) {
    180             Caches::getInstance().textureCache.releaseTexture(resource);
    181         }
    182         delete resource;
    183         return;
    184     }
    185     ref->destroyed = true;
    186     if (ref->refCount == 0) {
    187         deleteResourceReferenceLocked(resource, ref);
    188     }
    189 }
    190 
    191 void ResourceCache::destructor(Res_png_9patch* resource) {
    192     Mutex::Autolock _l(mLock);
    193     destructorLocked(resource);
    194 }
    195 
    196 void ResourceCache::destructorLocked(Res_png_9patch* resource) {
    197     ssize_t index = mCache->indexOfKey(resource);
    198     ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
    199     if (ref == NULL) {
    200         // If we're not tracking this resource, just delete it
    201         if (Caches::hasInstance()) {
    202             Caches::getInstance().patchCache.removeDeferred(resource);
    203         } else {
    204             // A Res_png_9patch is actually an array of byte that's larger
    205             // than sizeof(Res_png_9patch). It must be freed as an array.
    206             delete[] (int8_t*) resource;
    207         }
    208         return;
    209     }
    210     ref->destroyed = true;
    211     if (ref->refCount == 0) {
    212         deleteResourceReferenceLocked(resource, ref);
    213     }
    214 }
    215 
    216 /**
    217  * Return value indicates whether resource was actually recycled, which happens when RefCnt
    218  * reaches 0.
    219  */
    220 bool ResourceCache::recycle(SkBitmap* resource) {
    221     Mutex::Autolock _l(mLock);
    222     return recycleLocked(resource);
    223 }
    224 
    225 /**
    226  * Return value indicates whether resource was actually recycled, which happens when RefCnt
    227  * reaches 0.
    228  */
    229 bool ResourceCache::recycleLocked(SkBitmap* resource) {
    230     ssize_t index = mCache->indexOfKey(resource);
    231     if (index < 0) {
    232         if (Caches::hasInstance()) {
    233             Caches::getInstance().textureCache.releaseTexture(resource);
    234         }
    235         // not tracking this resource; just recycle the pixel data
    236         resource->setPixels(NULL, NULL);
    237         return true;
    238     }
    239     ResourceReference* ref = mCache->valueAt(index);
    240     if (ref == NULL) {
    241         // Should not get here - shouldn't get a call to recycle if we're not yet tracking it
    242         return true;
    243     }
    244     ref->recycled = true;
    245     if (ref->refCount == 0) {
    246         deleteResourceReferenceLocked(resource, ref);
    247         return true;
    248     }
    249     // Still referring to resource, don't recycle yet
    250     return false;
    251 }
    252 
    253 /**
    254  * This method should only be called while the mLock mutex is held (that mutex is grabbed
    255  * by the various destructor() and recycle() methods which call this method).
    256  */
    257 void ResourceCache::deleteResourceReferenceLocked(const void* resource, ResourceReference* ref) {
    258     if (ref->recycled && ref->resourceType == kBitmap) {
    259         SkBitmap* bitmap = (SkBitmap*) resource;
    260         if (Caches::hasInstance()) {
    261             Caches::getInstance().textureCache.releaseTexture(bitmap);
    262         }
    263         bitmap->setPixels(NULL, NULL);
    264     }
    265     if (ref->destroyed) {
    266         switch (ref->resourceType) {
    267             case kBitmap: {
    268                 SkBitmap* bitmap = (SkBitmap*) resource;
    269                 if (Caches::hasInstance()) {
    270                     Caches::getInstance().textureCache.releaseTexture(bitmap);
    271                 }
    272                 delete bitmap;
    273             }
    274             break;
    275             case kPath: {
    276                 SkPath* path = (SkPath*) resource;
    277                 if (Caches::hasInstance()) {
    278                     Caches::getInstance().pathCache.removeDeferred(path);
    279                 } else {
    280                     delete path;
    281                 }
    282             }
    283             break;
    284             case kNinePatch: {
    285                 if (Caches::hasInstance()) {
    286                     Caches::getInstance().patchCache.removeDeferred((Res_png_9patch*) resource);
    287                 } else {
    288                     // A Res_png_9patch is actually an array of byte that's larger
    289                     // than sizeof(Res_png_9patch). It must be freed as an array.
    290                     int8_t* patch = (int8_t*) resource;
    291                     delete[] patch;
    292                 }
    293             }
    294             break;
    295         }
    296     }
    297     mCache->removeItem(resource);
    298     delete ref;
    299 }
    300 
    301 }; // namespace uirenderer
    302 }; // namespace android
    303