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