ResourceCache.cpp revision e4ac2d6b5723c95e648c489b187ddde449452c13
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
21namespace android {
22namespace uirenderer {
23
24///////////////////////////////////////////////////////////////////////////////
25// Resource cache
26///////////////////////////////////////////////////////////////////////////////
27
28void ResourceCache::logCache() {
29    LOGD("ResourceCache: cacheReport:");
30    for (size_t i = 0; i < mCache->size(); ++i) {
31        ResourceReference* ref = mCache->valueAt(i);
32        LOGD("  ResourceCache: mCache(%d): resource, ref = 0x%p, 0x%p",
33                i, mCache->keyAt(i), mCache->valueAt(i));
34        LOGD("  ResourceCache: mCache(%d): refCount, recycled, destroyed, type = %d, %d, %d, %d",
35                i, ref->refCount, ref->recycled, ref->destroyed, ref->resourceType);
36    }
37}
38
39ResourceCache::ResourceCache() {
40    Mutex::Autolock _l(mLock);
41    mCache = new KeyedVector<void *, ResourceReference *>();
42}
43
44ResourceCache::~ResourceCache() {
45    Mutex::Autolock _l(mLock);
46    delete mCache;
47}
48
49void ResourceCache::incrementRefcount(void* resource, ResourceType resourceType) {
50    Mutex::Autolock _l(mLock);
51    for (size_t i = 0; i < mCache->size(); ++i) {
52        void* ref = mCache->valueAt(i);
53    }
54    ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL;
55    if (ref == NULL || mCache->size() == 0) {
56        ref = new ResourceReference(resourceType);
57        mCache->add(resource, ref);
58    }
59    ref->refCount++;
60}
61
62void ResourceCache::incrementRefcount(SkBitmap* bitmapResource) {
63    SkPixelRef* pixref = bitmapResource->pixelRef();
64    if (pixref) pixref->globalRef();
65
66    bitmapResource->getColorTable()->safeRef();
67    incrementRefcount((void*)bitmapResource, kBitmap);
68}
69
70void ResourceCache::incrementRefcount(SkiaShader* shaderResource) {
71    shaderResource->getSkShader()->safeRef();
72    incrementRefcount((void*)shaderResource, kShader);
73}
74
75void ResourceCache::incrementRefcount(SkiaColorFilter* filterResource) {
76    filterResource->getSkColorFilter()->safeRef();
77    incrementRefcount((void*)filterResource, kColorFilter);
78}
79
80void ResourceCache::decrementRefcount(void* resource) {
81    Mutex::Autolock _l(mLock);
82    ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL;
83    if (ref == NULL) {
84        // Should not get here - shouldn't get a call to decrement if we're not yet tracking it
85        return;
86    }
87    ref->refCount--;
88    if (ref->refCount == 0) {
89        deleteResourceReference(resource, ref);
90    }
91}
92
93void ResourceCache::decrementRefcount(SkBitmap* bitmapResource) {
94    SkPixelRef* pixref = bitmapResource->pixelRef();
95    if (pixref) pixref->globalUnref();
96
97    bitmapResource->getColorTable()->safeUnref();
98    decrementRefcount((void*)bitmapResource);
99}
100
101void ResourceCache::decrementRefcount(SkiaShader* shaderResource) {
102    shaderResource->getSkShader()->safeUnref();
103    decrementRefcount((void*)shaderResource);
104}
105
106void ResourceCache::decrementRefcount(SkiaColorFilter* filterResource) {
107    filterResource->getSkColorFilter()->safeUnref();
108    decrementRefcount((void*)filterResource);
109}
110
111void ResourceCache::recycle(SkBitmap* resource) {
112    Mutex::Autolock _l(mLock);
113    if (mCache->indexOfKey(resource) < 0) {
114        // not tracking this resource; just recycle the pixel data
115        resource->setPixels(NULL, NULL);
116        return;
117    }
118    ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL;
119    if (ref == NULL) {
120        // Should not get here - shouldn't get a call to recycle if we're not yet tracking it
121        return;
122    }
123    ref->recycled = true;
124    if (ref->refCount == 0) {
125        deleteResourceReference(resource, ref);
126    }
127}
128
129void ResourceCache::destructor(SkBitmap* resource) {
130    Mutex::Autolock _l(mLock);
131    ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL;
132    if (ref == NULL) {
133        // If we're not tracking this resource, just delete it
134        if (Caches::hasInstance()) {
135            Caches::getInstance().textureCache.removeDeferred(resource);
136        }
137        delete resource;
138        return;
139    }
140    ref->destroyed = true;
141    if (ref->refCount == 0) {
142        deleteResourceReference(resource, ref);
143        return;
144    }
145}
146
147void ResourceCache::destructor(SkiaShader* 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().gradientCache.removeDeferred(resource->getSkShader());
154        }
155        delete resource;
156        return;
157    }
158    ref->destroyed = true;
159    if (ref->refCount == 0) {
160        deleteResourceReference(resource, ref);
161        return;
162    }
163}
164
165void ResourceCache::destructor(SkiaColorFilter* resource) {
166    Mutex::Autolock _l(mLock);
167    ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL;
168    if (ref == NULL) {
169        // If we're not tracking this resource, just delete it
170        delete resource;
171        return;
172    }
173    ref->destroyed = true;
174    if (ref->refCount == 0) {
175        deleteResourceReference(resource, ref);
176        return;
177    }
178}
179
180/**
181 * This method should only be called while the mLock mutex is held (that mutex is grabbed
182 * by the various destructor() and recycle() methods which call this method).
183 */
184void ResourceCache::deleteResourceReference(void* resource, ResourceReference* ref) {
185    if (ref->recycled && ref->resourceType == kBitmap) {
186        ((SkBitmap*) resource)->setPixels(NULL, NULL);
187    }
188    if (ref->destroyed) {
189        switch (ref->resourceType) {
190            case kBitmap:
191            {
192                SkBitmap* bitmap = (SkBitmap*)resource;
193                if (Caches::hasInstance()) {
194                    Caches::getInstance().textureCache.removeDeferred(bitmap);
195                }
196                delete bitmap;
197            }
198            break;
199            case kShader:
200            {
201                SkiaShader* shader = (SkiaShader*)resource;
202                if (Caches::hasInstance()) {
203                    Caches::getInstance().gradientCache.removeDeferred(shader->getSkShader());
204                }
205                delete shader;
206            }
207            break;
208            case kColorFilter:
209            {
210                SkiaColorFilter* filter = (SkiaColorFilter*)resource;
211                delete filter;
212            }
213            break;
214        }
215    }
216    mCache->removeItem(resource);
217    delete ref;
218}
219
220}; // namespace uirenderer
221}; // namespace android
222