• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
23 namespace android {
24 
25 #ifdef USE_OPENGL_RENDERER
26 using namespace uirenderer;
27 ANDROID_SINGLETON_STATIC_INSTANCE(ResourceCache);
28 #endif
29 
30 namespace uirenderer {
31 
32 ///////////////////////////////////////////////////////////////////////////////
33 // Resource cache
34 ///////////////////////////////////////////////////////////////////////////////
35 
logCache()36 void ResourceCache::logCache() {
37     ALOGD("ResourceCache: cacheReport:");
38     for (size_t i = 0; i < mCache->size(); ++i) {
39         ResourceReference* ref = mCache->valueAt(i);
40         ALOGD("  ResourceCache: mCache(%zu): resource, ref = 0x%p, 0x%p",
41                 i, mCache->keyAt(i), mCache->valueAt(i));
42         ALOGD("  ResourceCache: mCache(%zu): refCount, recycled, destroyed, type = %d, %d, %d, %d",
43                 i, ref->refCount, ref->recycled, ref->destroyed, ref->resourceType);
44     }
45 }
46 
ResourceCache()47 ResourceCache::ResourceCache() {
48     Mutex::Autolock _l(mLock);
49     mCache = new KeyedVector<const void*, ResourceReference*>();
50 }
51 
~ResourceCache()52 ResourceCache::~ResourceCache() {
53     Mutex::Autolock _l(mLock);
54     delete mCache;
55 }
56 
lock()57 void ResourceCache::lock() {
58     mLock.lock();
59 }
60 
unlock()61 void ResourceCache::unlock() {
62     mLock.unlock();
63 }
64 
incrementRefcount(void * resource,ResourceType resourceType)65 void ResourceCache::incrementRefcount(void* resource, ResourceType resourceType) {
66     Mutex::Autolock _l(mLock);
67     incrementRefcountLocked(resource, resourceType);
68 }
69 
incrementRefcount(const SkBitmap * bitmapResource)70 void ResourceCache::incrementRefcount(const SkBitmap* bitmapResource) {
71     incrementRefcount((void*) bitmapResource, kBitmap);
72 }
73 
incrementRefcount(const SkPath * pathResource)74 void ResourceCache::incrementRefcount(const SkPath* pathResource) {
75     incrementRefcount((void*) pathResource, kPath);
76 }
77 
incrementRefcount(const Res_png_9patch * patchResource)78 void ResourceCache::incrementRefcount(const Res_png_9patch* patchResource) {
79     incrementRefcount((void*) patchResource, kNinePatch);
80 }
81 
incrementRefcountLocked(void * resource,ResourceType resourceType)82 void ResourceCache::incrementRefcountLocked(void* resource, ResourceType resourceType) {
83     ssize_t index = mCache->indexOfKey(resource);
84     ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
85     if (ref == NULL || mCache->size() == 0) {
86         ref = new ResourceReference(resourceType);
87         mCache->add(resource, ref);
88     }
89     ref->refCount++;
90 }
91 
incrementRefcountLocked(const SkBitmap * bitmapResource)92 void ResourceCache::incrementRefcountLocked(const SkBitmap* bitmapResource) {
93     incrementRefcountLocked((void*) bitmapResource, kBitmap);
94 }
95 
incrementRefcountLocked(const SkPath * pathResource)96 void ResourceCache::incrementRefcountLocked(const SkPath* pathResource) {
97     incrementRefcountLocked((void*) pathResource, kPath);
98 }
99 
incrementRefcountLocked(const Res_png_9patch * patchResource)100 void ResourceCache::incrementRefcountLocked(const Res_png_9patch* patchResource) {
101     incrementRefcountLocked((void*) patchResource, kNinePatch);
102 }
103 
decrementRefcount(void * resource)104 void ResourceCache::decrementRefcount(void* resource) {
105     Mutex::Autolock _l(mLock);
106     decrementRefcountLocked(resource);
107 }
108 
decrementRefcount(const SkBitmap * bitmapResource)109 void ResourceCache::decrementRefcount(const SkBitmap* bitmapResource) {
110     decrementRefcount((void*) bitmapResource);
111 }
112 
decrementRefcount(const SkPath * pathResource)113 void ResourceCache::decrementRefcount(const SkPath* pathResource) {
114     decrementRefcount((void*) pathResource);
115 }
116 
decrementRefcount(const Res_png_9patch * patchResource)117 void ResourceCache::decrementRefcount(const Res_png_9patch* patchResource) {
118     decrementRefcount((void*) patchResource);
119 }
120 
decrementRefcountLocked(void * resource)121 void ResourceCache::decrementRefcountLocked(void* resource) {
122     ssize_t index = mCache->indexOfKey(resource);
123     ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
124     if (ref == NULL) {
125         // Should not get here - shouldn't get a call to decrement if we're not yet tracking it
126         return;
127     }
128     ref->refCount--;
129     if (ref->refCount == 0) {
130         deleteResourceReferenceLocked(resource, ref);
131     }
132 }
133 
decrementRefcountLocked(const SkBitmap * bitmapResource)134 void ResourceCache::decrementRefcountLocked(const SkBitmap* bitmapResource) {
135     decrementRefcountLocked((void*) bitmapResource);
136 }
137 
decrementRefcountLocked(const SkPath * pathResource)138 void ResourceCache::decrementRefcountLocked(const SkPath* pathResource) {
139     decrementRefcountLocked((void*) pathResource);
140 }
141 
decrementRefcountLocked(const Res_png_9patch * patchResource)142 void ResourceCache::decrementRefcountLocked(const Res_png_9patch* patchResource) {
143     decrementRefcountLocked((void*) patchResource);
144 }
145 
destructor(SkPath * resource)146 void ResourceCache::destructor(SkPath* resource) {
147     Mutex::Autolock _l(mLock);
148     destructorLocked(resource);
149 }
150 
destructorLocked(SkPath * resource)151 void ResourceCache::destructorLocked(SkPath* resource) {
152     ssize_t index = mCache->indexOfKey(resource);
153     ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
154     if (ref == NULL) {
155         // If we're not tracking this resource, just delete it
156         if (Caches::hasInstance()) {
157             Caches::getInstance().pathCache.removeDeferred(resource);
158         } else {
159             delete resource;
160         }
161         return;
162     }
163     ref->destroyed = true;
164     if (ref->refCount == 0) {
165         deleteResourceReferenceLocked(resource, ref);
166     }
167 }
168 
destructor(const SkBitmap * resource)169 void ResourceCache::destructor(const SkBitmap* resource) {
170     Mutex::Autolock _l(mLock);
171     destructorLocked(resource);
172 }
173 
destructorLocked(const SkBitmap * resource)174 void ResourceCache::destructorLocked(const SkBitmap* resource) {
175     ssize_t index = mCache->indexOfKey(resource);
176     ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
177     if (ref == NULL) {
178         // If we're not tracking this resource, just delete it
179         if (Caches::hasInstance()) {
180             Caches::getInstance().textureCache.releaseTexture(resource);
181         }
182         delete resource;
183         return;
184     }
185     ref->destroyed = true;
186     if (ref->refCount == 0) {
187         deleteResourceReferenceLocked(resource, ref);
188     }
189 }
190 
destructor(Res_png_9patch * resource)191 void ResourceCache::destructor(Res_png_9patch* resource) {
192     Mutex::Autolock _l(mLock);
193     destructorLocked(resource);
194 }
195 
destructorLocked(Res_png_9patch * resource)196 void ResourceCache::destructorLocked(Res_png_9patch* resource) {
197     ssize_t index = mCache->indexOfKey(resource);
198     ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
199     if (ref == NULL) {
200         // If we're not tracking this resource, just delete it
201         if (Caches::hasInstance()) {
202             Caches::getInstance().patchCache.removeDeferred(resource);
203         } else {
204             // A Res_png_9patch is actually an array of byte that's larger
205             // than sizeof(Res_png_9patch). It must be freed as an array.
206             delete[] (int8_t*) resource;
207         }
208         return;
209     }
210     ref->destroyed = true;
211     if (ref->refCount == 0) {
212         deleteResourceReferenceLocked(resource, ref);
213     }
214 }
215 
216 /**
217  * Return value indicates whether resource was actually recycled, which happens when RefCnt
218  * reaches 0.
219  */
recycle(SkBitmap * resource)220 bool ResourceCache::recycle(SkBitmap* resource) {
221     Mutex::Autolock _l(mLock);
222     return recycleLocked(resource);
223 }
224 
225 /**
226  * Return value indicates whether resource was actually recycled, which happens when RefCnt
227  * reaches 0.
228  */
recycleLocked(SkBitmap * resource)229 bool ResourceCache::recycleLocked(SkBitmap* resource) {
230     ssize_t index = mCache->indexOfKey(resource);
231     if (index < 0) {
232         if (Caches::hasInstance()) {
233             Caches::getInstance().textureCache.releaseTexture(resource);
234         }
235         // not tracking this resource; just recycle the pixel data
236         resource->setPixels(NULL, NULL);
237         return true;
238     }
239     ResourceReference* ref = mCache->valueAt(index);
240     if (ref == NULL) {
241         // Should not get here - shouldn't get a call to recycle if we're not yet tracking it
242         return true;
243     }
244     ref->recycled = true;
245     if (ref->refCount == 0) {
246         deleteResourceReferenceLocked(resource, ref);
247         return true;
248     }
249     // Still referring to resource, don't recycle yet
250     return false;
251 }
252 
253 /**
254  * This method should only be called while the mLock mutex is held (that mutex is grabbed
255  * by the various destructor() and recycle() methods which call this method).
256  */
deleteResourceReferenceLocked(const void * resource,ResourceReference * ref)257 void ResourceCache::deleteResourceReferenceLocked(const void* resource, ResourceReference* ref) {
258     if (ref->recycled && ref->resourceType == kBitmap) {
259         SkBitmap* bitmap = (SkBitmap*) resource;
260         if (Caches::hasInstance()) {
261             Caches::getInstance().textureCache.releaseTexture(bitmap);
262         }
263         bitmap->setPixels(NULL, NULL);
264     }
265     if (ref->destroyed) {
266         switch (ref->resourceType) {
267             case kBitmap: {
268                 SkBitmap* bitmap = (SkBitmap*) resource;
269                 if (Caches::hasInstance()) {
270                     Caches::getInstance().textureCache.releaseTexture(bitmap);
271                 }
272                 delete bitmap;
273             }
274             break;
275             case kPath: {
276                 SkPath* path = (SkPath*) resource;
277                 if (Caches::hasInstance()) {
278                     Caches::getInstance().pathCache.removeDeferred(path);
279                 } else {
280                     delete path;
281                 }
282             }
283             break;
284             case kNinePatch: {
285                 if (Caches::hasInstance()) {
286                     Caches::getInstance().patchCache.removeDeferred((Res_png_9patch*) resource);
287                 } else {
288                     // A Res_png_9patch is actually an array of byte that's larger
289                     // than sizeof(Res_png_9patch). It must be freed as an array.
290                     int8_t* patch = (int8_t*) resource;
291                     delete[] patch;
292                 }
293             }
294             break;
295         }
296     }
297     mCache->removeItem(resource);
298     delete ref;
299 }
300 
301 }; // namespace uirenderer
302 }; // namespace android
303