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