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