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
21 namespace android {
22 namespace uirenderer {
23
24 ///////////////////////////////////////////////////////////////////////////////
25 // Resource cache
26 ///////////////////////////////////////////////////////////////////////////////
27
logCache()28 void 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
ResourceCache()39 ResourceCache::ResourceCache() {
40 Mutex::Autolock _l(mLock);
41 mCache = new KeyedVector<void*, ResourceReference*>();
42 }
43
~ResourceCache()44 ResourceCache::~ResourceCache() {
45 Mutex::Autolock _l(mLock);
46 delete mCache;
47 }
48
lock()49 void ResourceCache::lock() {
50 mLock.lock();
51 }
52
unlock()53 void ResourceCache::unlock() {
54 mLock.unlock();
55 }
56
incrementRefcount(void * resource,ResourceType resourceType)57 void ResourceCache::incrementRefcount(void* resource, ResourceType resourceType) {
58 Mutex::Autolock _l(mLock);
59 incrementRefcountLocked(resource, resourceType);
60 }
61
incrementRefcount(SkBitmap * bitmapResource)62 void ResourceCache::incrementRefcount(SkBitmap* bitmapResource) {
63 SkSafeRef(bitmapResource->pixelRef());
64 SkSafeRef(bitmapResource->getColorTable());
65 incrementRefcount((void*) bitmapResource, kBitmap);
66 }
67
incrementRefcount(SkPath * pathResource)68 void ResourceCache::incrementRefcount(SkPath* pathResource) {
69 incrementRefcount((void*) pathResource, kPath);
70 }
71
incrementRefcount(SkiaShader * shaderResource)72 void ResourceCache::incrementRefcount(SkiaShader* shaderResource) {
73 SkSafeRef(shaderResource->getSkShader());
74 incrementRefcount((void*) shaderResource, kShader);
75 }
76
incrementRefcount(SkiaColorFilter * filterResource)77 void ResourceCache::incrementRefcount(SkiaColorFilter* filterResource) {
78 SkSafeRef(filterResource->getSkColorFilter());
79 incrementRefcount((void*) filterResource, kColorFilter);
80 }
81
incrementRefcount(Layer * layerResource)82 void ResourceCache::incrementRefcount(Layer* layerResource) {
83 incrementRefcount((void*) layerResource, kLayer);
84 }
85
incrementRefcountLocked(void * resource,ResourceType resourceType)86 void ResourceCache::incrementRefcountLocked(void* resource, ResourceType resourceType) {
87 ssize_t index = mCache->indexOfKey(resource);
88 ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
89 if (ref == NULL || mCache->size() == 0) {
90 ref = new ResourceReference(resourceType);
91 mCache->add(resource, ref);
92 }
93 ref->refCount++;
94 }
95
incrementRefcountLocked(SkBitmap * bitmapResource)96 void ResourceCache::incrementRefcountLocked(SkBitmap* bitmapResource) {
97 SkSafeRef(bitmapResource->pixelRef());
98 SkSafeRef(bitmapResource->getColorTable());
99 incrementRefcountLocked((void*) bitmapResource, kBitmap);
100 }
101
incrementRefcountLocked(SkPath * pathResource)102 void ResourceCache::incrementRefcountLocked(SkPath* pathResource) {
103 incrementRefcountLocked((void*) pathResource, kPath);
104 }
105
incrementRefcountLocked(SkiaShader * shaderResource)106 void ResourceCache::incrementRefcountLocked(SkiaShader* shaderResource) {
107 SkSafeRef(shaderResource->getSkShader());
108 incrementRefcountLocked((void*) shaderResource, kShader);
109 }
110
incrementRefcountLocked(SkiaColorFilter * filterResource)111 void ResourceCache::incrementRefcountLocked(SkiaColorFilter* filterResource) {
112 SkSafeRef(filterResource->getSkColorFilter());
113 incrementRefcountLocked((void*) filterResource, kColorFilter);
114 }
115
incrementRefcountLocked(Layer * layerResource)116 void ResourceCache::incrementRefcountLocked(Layer* layerResource) {
117 incrementRefcountLocked((void*) layerResource, kLayer);
118 }
119
decrementRefcount(void * resource)120 void ResourceCache::decrementRefcount(void* resource) {
121 Mutex::Autolock _l(mLock);
122 decrementRefcountLocked(resource);
123 }
124
decrementRefcount(SkBitmap * bitmapResource)125 void ResourceCache::decrementRefcount(SkBitmap* bitmapResource) {
126 SkSafeUnref(bitmapResource->pixelRef());
127 SkSafeUnref(bitmapResource->getColorTable());
128 decrementRefcount((void*) bitmapResource);
129 }
130
decrementRefcount(SkPath * pathResource)131 void ResourceCache::decrementRefcount(SkPath* pathResource) {
132 decrementRefcount((void*) pathResource);
133 }
134
decrementRefcount(SkiaShader * shaderResource)135 void ResourceCache::decrementRefcount(SkiaShader* shaderResource) {
136 SkSafeUnref(shaderResource->getSkShader());
137 decrementRefcount((void*) shaderResource);
138 }
139
decrementRefcount(SkiaColorFilter * filterResource)140 void ResourceCache::decrementRefcount(SkiaColorFilter* filterResource) {
141 SkSafeUnref(filterResource->getSkColorFilter());
142 decrementRefcount((void*) filterResource);
143 }
144
decrementRefcount(Layer * layerResource)145 void ResourceCache::decrementRefcount(Layer* layerResource) {
146 decrementRefcount((void*) layerResource);
147 }
148
decrementRefcountLocked(void * resource)149 void ResourceCache::decrementRefcountLocked(void* resource) {
150 ssize_t index = mCache->indexOfKey(resource);
151 ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
152 if (ref == NULL) {
153 // Should not get here - shouldn't get a call to decrement if we're not yet tracking it
154 return;
155 }
156 ref->refCount--;
157 if (ref->refCount == 0) {
158 deleteResourceReferenceLocked(resource, ref);
159 }
160 }
161
decrementRefcountLocked(SkBitmap * bitmapResource)162 void ResourceCache::decrementRefcountLocked(SkBitmap* bitmapResource) {
163 SkSafeUnref(bitmapResource->pixelRef());
164 SkSafeUnref(bitmapResource->getColorTable());
165 decrementRefcountLocked((void*) bitmapResource);
166 }
167
decrementRefcountLocked(SkPath * pathResource)168 void ResourceCache::decrementRefcountLocked(SkPath* pathResource) {
169 decrementRefcountLocked((void*) pathResource);
170 }
171
decrementRefcountLocked(SkiaShader * shaderResource)172 void ResourceCache::decrementRefcountLocked(SkiaShader* shaderResource) {
173 SkSafeUnref(shaderResource->getSkShader());
174 decrementRefcountLocked((void*) shaderResource);
175 }
176
decrementRefcountLocked(SkiaColorFilter * filterResource)177 void ResourceCache::decrementRefcountLocked(SkiaColorFilter* filterResource) {
178 SkSafeUnref(filterResource->getSkColorFilter());
179 decrementRefcountLocked((void*) filterResource);
180 }
181
decrementRefcountLocked(Layer * layerResource)182 void ResourceCache::decrementRefcountLocked(Layer* layerResource) {
183 decrementRefcountLocked((void*) layerResource);
184 }
185
destructor(SkPath * resource)186 void ResourceCache::destructor(SkPath* resource) {
187 Mutex::Autolock _l(mLock);
188 destructorLocked(resource);
189 }
190
destructorLocked(SkPath * resource)191 void ResourceCache::destructorLocked(SkPath* resource) {
192 ssize_t index = mCache->indexOfKey(resource);
193 ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
194 if (ref == NULL) {
195 // If we're not tracking this resource, just delete it
196 if (Caches::hasInstance()) {
197 Caches::getInstance().pathCache.removeDeferred(resource);
198 }
199 delete resource;
200 return;
201 }
202 ref->destroyed = true;
203 if (ref->refCount == 0) {
204 deleteResourceReferenceLocked(resource, ref);
205 }
206 }
207
destructor(SkBitmap * resource)208 void ResourceCache::destructor(SkBitmap* resource) {
209 Mutex::Autolock _l(mLock);
210 destructorLocked(resource);
211 }
212
destructorLocked(SkBitmap * resource)213 void ResourceCache::destructorLocked(SkBitmap* resource) {
214 ssize_t index = mCache->indexOfKey(resource);
215 ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
216 if (ref == NULL) {
217 // If we're not tracking this resource, just delete it
218 if (Caches::hasInstance()) {
219 Caches::getInstance().textureCache.removeDeferred(resource);
220 }
221 delete resource;
222 return;
223 }
224 ref->destroyed = true;
225 if (ref->refCount == 0) {
226 deleteResourceReferenceLocked(resource, ref);
227 }
228 }
229
destructor(SkiaShader * resource)230 void ResourceCache::destructor(SkiaShader* resource) {
231 Mutex::Autolock _l(mLock);
232 destructorLocked(resource);
233 }
234
destructorLocked(SkiaShader * resource)235 void ResourceCache::destructorLocked(SkiaShader* resource) {
236 ssize_t index = mCache->indexOfKey(resource);
237 ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
238 if (ref == NULL) {
239 // If we're not tracking this resource, just delete it
240 delete resource;
241 return;
242 }
243 ref->destroyed = true;
244 if (ref->refCount == 0) {
245 deleteResourceReferenceLocked(resource, ref);
246 }
247 }
248
destructor(SkiaColorFilter * resource)249 void ResourceCache::destructor(SkiaColorFilter* resource) {
250 Mutex::Autolock _l(mLock);
251 destructorLocked(resource);
252 }
253
destructorLocked(SkiaColorFilter * resource)254 void ResourceCache::destructorLocked(SkiaColorFilter* resource) {
255 ssize_t index = mCache->indexOfKey(resource);
256 ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
257 if (ref == NULL) {
258 // If we're not tracking this resource, just delete it
259 delete resource;
260 return;
261 }
262 ref->destroyed = true;
263 if (ref->refCount == 0) {
264 deleteResourceReferenceLocked(resource, ref);
265 }
266 }
267
268 /**
269 * Return value indicates whether resource was actually recycled, which happens when RefCnt
270 * reaches 0.
271 */
recycle(SkBitmap * resource)272 bool ResourceCache::recycle(SkBitmap* resource) {
273 Mutex::Autolock _l(mLock);
274 return recycleLocked(resource);
275 }
276
277 /**
278 * Return value indicates whether resource was actually recycled, which happens when RefCnt
279 * reaches 0.
280 */
recycleLocked(SkBitmap * resource)281 bool ResourceCache::recycleLocked(SkBitmap* resource) {
282 ssize_t index = mCache->indexOfKey(resource);
283 if (index < 0) {
284 // not tracking this resource; just recycle the pixel data
285 resource->setPixels(NULL, NULL);
286 return true;
287 }
288 ResourceReference* ref = mCache->valueAt(index);
289 if (ref == NULL) {
290 // Should not get here - shouldn't get a call to recycle if we're not yet tracking it
291 return true;
292 }
293 ref->recycled = true;
294 if (ref->refCount == 0) {
295 deleteResourceReferenceLocked(resource, ref);
296 return true;
297 }
298 // Still referring to resource, don't recycle yet
299 return false;
300 }
301
302 /**
303 * This method should only be called while the mLock mutex is held (that mutex is grabbed
304 * by the various destructor() and recycle() methods which call this method).
305 */
deleteResourceReferenceLocked(void * resource,ResourceReference * ref)306 void ResourceCache::deleteResourceReferenceLocked(void* resource, ResourceReference* ref) {
307 if (ref->recycled && ref->resourceType == kBitmap) {
308 ((SkBitmap*) resource)->setPixels(NULL, NULL);
309 }
310 if (ref->destroyed || ref->resourceType == kLayer) {
311 switch (ref->resourceType) {
312 case kBitmap: {
313 SkBitmap* bitmap = (SkBitmap*) resource;
314 if (Caches::hasInstance()) {
315 Caches::getInstance().textureCache.removeDeferred(bitmap);
316 }
317 delete bitmap;
318 }
319 break;
320 case kPath: {
321 SkPath* path = (SkPath*) resource;
322 if (Caches::hasInstance()) {
323 Caches::getInstance().pathCache.removeDeferred(path);
324 }
325 delete path;
326 }
327 break;
328 case kShader: {
329 SkiaShader* shader = (SkiaShader*) resource;
330 delete shader;
331 }
332 break;
333 case kColorFilter: {
334 SkiaColorFilter* filter = (SkiaColorFilter*) resource;
335 delete filter;
336 }
337 break;
338 case kLayer: {
339 Layer* layer = (Layer*) resource;
340 Caches::getInstance().deleteLayerDeferred(layer);
341 }
342 break;
343 }
344 }
345 mCache->removeItem(resource);
346 delete ref;
347 }
348
349 }; // namespace uirenderer
350 }; // namespace android
351