ResourceCache.cpp revision 5a7e828842c26f64bb6e0ef3e0019e1949b245ee
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    bitmapResource->pixelRef()->safeRef();
64    bitmapResource->getColorTable()->safeRef();
65    incrementRefcount((void*)bitmapResource, kBitmap);
66}
67
68void ResourceCache::incrementRefcount(SkPath* pathResource) {
69    incrementRefcount((void*)pathResource, kPath);
70}
71
72void ResourceCache::incrementRefcount(SkiaShader* shaderResource) {
73    shaderResource->getSkShader()->safeRef();
74    incrementRefcount((void*) shaderResource, kShader);
75}
76
77void ResourceCache::incrementRefcount(SkiaColorFilter* filterResource) {
78    filterResource->getSkColorFilter()->safeRef();
79    incrementRefcount((void*) filterResource, kColorFilter);
80}
81
82void ResourceCache::decrementRefcount(void* resource) {
83    Mutex::Autolock _l(mLock);
84    ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL;
85    if (ref == NULL) {
86        // Should not get here - shouldn't get a call to decrement if we're not yet tracking it
87        return;
88    }
89    ref->refCount--;
90    if (ref->refCount == 0) {
91        deleteResourceReference(resource, ref);
92    }
93}
94
95void ResourceCache::decrementRefcount(SkBitmap* bitmapResource) {
96    bitmapResource->pixelRef()->safeUnref();
97    bitmapResource->getColorTable()->safeUnref();
98    decrementRefcount((void*) bitmapResource);
99}
100
101void ResourceCache::decrementRefcount(SkPath* pathResource) {
102    decrementRefcount((void*) pathResource);
103}
104
105void ResourceCache::decrementRefcount(SkiaShader* shaderResource) {
106    shaderResource->getSkShader()->safeUnref();
107    decrementRefcount((void*) shaderResource);
108}
109
110void ResourceCache::decrementRefcount(SkiaColorFilter* filterResource) {
111    filterResource->getSkColorFilter()->safeUnref();
112    decrementRefcount((void*) filterResource);
113}
114
115void ResourceCache::recycle(SkBitmap* resource) {
116    Mutex::Autolock _l(mLock);
117    if (mCache->indexOfKey(resource) < 0) {
118        // not tracking this resource; just recycle the pixel data
119        resource->setPixels(NULL, NULL);
120        return;
121    }
122    ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL;
123    if (ref == NULL) {
124        // Should not get here - shouldn't get a call to recycle if we're not yet tracking it
125        return;
126    }
127    ref->recycled = true;
128    if (ref->refCount == 0) {
129        deleteResourceReference(resource, ref);
130    }
131}
132
133void ResourceCache::destructor(SkPath* resource) {
134    Mutex::Autolock _l(mLock);
135    ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL;
136    if (ref == NULL) {
137        // If we're not tracking this resource, just delete it
138        if (Caches::hasInstance()) {
139            Caches::getInstance().pathCache.removeDeferred(resource);
140        }
141        delete resource;
142        return;
143    }
144    ref->destroyed = true;
145    if (ref->refCount == 0) {
146        deleteResourceReference(resource, ref);
147        return;
148    }
149}
150
151void ResourceCache::destructor(SkBitmap* resource) {
152    Mutex::Autolock _l(mLock);
153    ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL;
154    if (ref == NULL) {
155        // If we're not tracking this resource, just delete it
156        if (Caches::hasInstance()) {
157            Caches::getInstance().textureCache.removeDeferred(resource);
158        }
159        delete resource;
160        return;
161    }
162    ref->destroyed = true;
163    if (ref->refCount == 0) {
164        deleteResourceReference(resource, ref);
165        return;
166    }
167}
168
169void ResourceCache::destructor(SkiaShader* resource) {
170    Mutex::Autolock _l(mLock);
171    ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL;
172    if (ref == NULL) {
173        // If we're not tracking this resource, just delete it
174        if (Caches::hasInstance()) {
175            Caches::getInstance().gradientCache.removeDeferred(resource->getSkShader());
176        }
177        delete resource;
178        return;
179    }
180    ref->destroyed = true;
181    if (ref->refCount == 0) {
182        deleteResourceReference(resource, ref);
183        return;
184    }
185}
186
187void ResourceCache::destructor(SkiaColorFilter* resource) {
188    Mutex::Autolock _l(mLock);
189    ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL;
190    if (ref == NULL) {
191        // If we're not tracking this resource, just delete it
192        delete resource;
193        return;
194    }
195    ref->destroyed = true;
196    if (ref->refCount == 0) {
197        deleteResourceReference(resource, ref);
198        return;
199    }
200}
201
202/**
203 * This method should only be called while the mLock mutex is held (that mutex is grabbed
204 * by the various destructor() and recycle() methods which call this method).
205 */
206void ResourceCache::deleteResourceReference(void* resource, ResourceReference* ref) {
207    if (ref->recycled && ref->resourceType == kBitmap) {
208        ((SkBitmap*) resource)->setPixels(NULL, NULL);
209    }
210    if (ref->destroyed) {
211        switch (ref->resourceType) {
212            case kBitmap:
213            {
214                SkBitmap* bitmap = (SkBitmap*)resource;
215                if (Caches::hasInstance()) {
216                    Caches::getInstance().textureCache.removeDeferred(bitmap);
217                }
218                delete bitmap;
219            }
220            break;
221            case kPath:
222            {
223                SkPath* path = (SkPath*)resource;
224                if (Caches::hasInstance()) {
225                    Caches::getInstance().pathCache.removeDeferred(path);
226                }
227                delete path;
228            }
229            break;
230            case kShader:
231            {
232                SkiaShader* shader = (SkiaShader*)resource;
233                if (Caches::hasInstance()) {
234                    Caches::getInstance().gradientCache.removeDeferred(shader->getSkShader());
235                }
236                delete shader;
237            }
238            break;
239            case kColorFilter:
240            {
241                SkiaColorFilter* filter = (SkiaColorFilter*)resource;
242                delete filter;
243            }
244            break;
245        }
246    }
247    mCache->removeItem(resource);
248    delete ref;
249}
250
251}; // namespace uirenderer
252}; // namespace android
253