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