• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2014 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "SkBitmapCache.h"
9 #include "SkImage.h"
10 #include "SkResourceCache.h"
11 #include "SkMipMap.h"
12 #include "SkPixelRef.h"
13 #include "SkRect.h"
14 
15 /**
16  *  Use this for bitmapcache and mipmapcache entries.
17  */
SkMakeResourceCacheSharedIDForBitmap(uint32_t bitmapGenID)18 uint64_t SkMakeResourceCacheSharedIDForBitmap(uint32_t bitmapGenID) {
19     uint64_t sharedID = SkSetFourByteTag('b', 'm', 'a', 'p');
20     return (sharedID << 32) | bitmapGenID;
21 }
22 
SkNotifyBitmapGenIDIsStale(uint32_t bitmapGenID)23 void SkNotifyBitmapGenIDIsStale(uint32_t bitmapGenID) {
24     SkResourceCache::PostPurgeSharedID(SkMakeResourceCacheSharedIDForBitmap(bitmapGenID));
25 }
26 
27 ///////////////////////////////////////////////////////////////////////////////////////////////////
28 
GetAllocator()29 SkBitmap::Allocator* SkBitmapCache::GetAllocator() {
30     return SkResourceCache::GetAllocator();
31 }
32 
33 /**
34  This function finds the bounds of the bitmap *within its pixelRef*.
35  If the bitmap lacks a pixelRef, it will return an empty rect, since
36  that doesn't make sense.  This may be a useful enough function that
37  it should be somewhere else (in SkBitmap?).
38  */
get_bounds_from_bitmap(const SkBitmap & bm)39 static SkIRect get_bounds_from_bitmap(const SkBitmap& bm) {
40     if (!(bm.pixelRef())) {
41         return SkIRect::MakeEmpty();
42     }
43     SkIPoint origin = bm.pixelRefOrigin();
44     return SkIRect::MakeXYWH(origin.fX, origin.fY, bm.width(), bm.height());
45 }
46 
47 /**
48  *  This function finds the bounds of the image. Today this is just the entire bounds,
49  *  but in the future we may support subsets within an image, in which case this should
50  *  return that subset (see get_bounds_from_bitmap).
51  */
get_bounds_from_image(const SkImage * image)52 static SkIRect get_bounds_from_image(const SkImage* image) {
53     return SkIRect::MakeWH(image->width(), image->height());
54 }
55 
Make(const SkBitmap & bm,int width,int height)56 SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkBitmap& bm, int width, int height) {
57     SkBitmapCacheDesc desc;
58     desc.fImageID = bm.getGenerationID();
59     desc.fWidth = width;
60     desc.fHeight = height;
61     desc.fBounds = get_bounds_from_bitmap(bm);
62     return desc;
63 }
64 
Make(const SkBitmap & bm)65 SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkBitmap& bm) {
66     return Make(bm, bm.width(), bm.height());
67 }
68 
Make(const SkImage * image,int width,int height)69 SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkImage* image, int width, int height) {
70     SkBitmapCacheDesc desc;
71     desc.fImageID = image->uniqueID();
72     desc.fWidth = width;
73     desc.fHeight = height;
74     desc.fBounds = get_bounds_from_image(image);
75     return desc;
76 }
77 
Make(const SkImage * image)78 SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkImage* image) {
79     return Make(image, image->width(), image->height());
80 }
81 
82 namespace {
83 static unsigned gBitmapKeyNamespaceLabel;
84 
85 struct BitmapKey : public SkResourceCache::Key {
86 public:
BitmapKey__anonac8b11c30111::BitmapKey87     BitmapKey(uint32_t genID, int width, int height, const SkIRect& bounds)
88         : fGenID(genID)
89         , fWidth(width)
90         , fHeight(height)
91         , fBounds(bounds)
92     {
93         this->init(&gBitmapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(fGenID),
94                    sizeof(fGenID) + sizeof(fWidth) + sizeof(fHeight) + sizeof(fBounds));
95     }
96 
BitmapKey__anonac8b11c30111::BitmapKey97     BitmapKey(const SkBitmapCacheDesc& desc)
98         : fGenID(desc.fImageID)
99         , fWidth(desc.fWidth)
100         , fHeight(desc.fHeight)
101         , fBounds(desc.fBounds)
102     {
103         this->init(&gBitmapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(fGenID),
104                    sizeof(fGenID) + sizeof(fWidth) + sizeof(fHeight) + sizeof(fBounds));
105     }
106 
dump__anonac8b11c30111::BitmapKey107     void dump() const {
108         SkDebugf("-- add [%d %d] %d [%d %d %d %d]\n", fWidth, fHeight, fGenID,
109                  fBounds.x(), fBounds.y(), fBounds.width(), fBounds.height());
110     }
111 
112     const uint32_t  fGenID;
113     const int       fWidth;
114     const int       fHeight;
115     const SkIRect   fBounds;
116 };
117 
118 struct BitmapRec : public SkResourceCache::Rec {
BitmapRec__anonac8b11c30111::BitmapRec119     BitmapRec(uint32_t genID, int width, int height, const SkIRect& bounds,
120               const SkBitmap& result)
121         : fKey(genID, width, height, bounds)
122         , fBitmap(result)
123     {
124 #ifdef TRACE_NEW_BITMAP_CACHE_RECS
125         fKey.dump();
126 #endif
127     }
128 
BitmapRec__anonac8b11c30111::BitmapRec129     BitmapRec(const SkBitmapCacheDesc& desc, const SkBitmap& result)
130         : fKey(desc)
131         , fBitmap(result)
132     {
133 #ifdef TRACE_NEW_BITMAP_CACHE_RECS
134         fKey.dump();
135 #endif
136     }
137 
getKey__anonac8b11c30111::BitmapRec138     const Key& getKey() const override { return fKey; }
bytesUsed__anonac8b11c30111::BitmapRec139     size_t bytesUsed() const override { return sizeof(fKey) + fBitmap.getSize(); }
140 
getCategory__anonac8b11c30111::BitmapRec141     const char* getCategory() const override { return "bitmap"; }
diagnostic_only_getDiscardable__anonac8b11c30111::BitmapRec142     SkDiscardableMemory* diagnostic_only_getDiscardable() const override {
143         return fBitmap.pixelRef()->diagnostic_only_getDiscardable();
144     }
145 
Finder__anonac8b11c30111::BitmapRec146     static bool Finder(const SkResourceCache::Rec& baseRec, void* contextBitmap) {
147         const BitmapRec& rec = static_cast<const BitmapRec&>(baseRec);
148         SkBitmap* result = (SkBitmap*)contextBitmap;
149 
150         *result = rec.fBitmap;
151         result->lockPixels();
152         return SkToBool(result->getPixels());
153     }
154 
155 private:
156     BitmapKey   fKey;
157     SkBitmap    fBitmap;
158 };
159 } // namespace
160 
161 #define CHECK_LOCAL(localCache, localName, globalName, ...) \
162     ((localCache) ? localCache->localName(__VA_ARGS__) : SkResourceCache::globalName(__VA_ARGS__))
163 
FindWH(const SkBitmapCacheDesc & desc,SkBitmap * result,SkResourceCache * localCache)164 bool SkBitmapCache::FindWH(const SkBitmapCacheDesc& desc, SkBitmap* result,
165                            SkResourceCache* localCache) {
166     if (0 == desc.fWidth || 0 == desc.fHeight) {
167         // degenerate
168         return false;
169     }
170     return CHECK_LOCAL(localCache, find, Find, BitmapKey(desc), BitmapRec::Finder, result);
171 }
172 
AddWH(const SkBitmapCacheDesc & desc,const SkBitmap & result,SkResourceCache * localCache)173 bool SkBitmapCache::AddWH(const SkBitmapCacheDesc& desc, const SkBitmap& result,
174                           SkResourceCache* localCache) {
175     if (0 == desc.fWidth || 0 == desc.fHeight) {
176         // degenerate, and the key we use for mipmaps
177         return false;
178     }
179     SkASSERT(result.isImmutable());
180     BitmapRec* rec = new BitmapRec(desc, result);
181     CHECK_LOCAL(localCache, add, Add, rec);
182     return true;
183 }
184 
Find(uint32_t genID,const SkIRect & subset,SkBitmap * result,SkResourceCache * localCache)185 bool SkBitmapCache::Find(uint32_t genID, const SkIRect& subset, SkBitmap* result,
186                          SkResourceCache* localCache) {
187     BitmapKey key(genID, SK_Scalar1, SK_Scalar1, subset);
188 
189     return CHECK_LOCAL(localCache, find, Find, key, BitmapRec::Finder, result);
190 }
191 
Add(SkPixelRef * pr,const SkIRect & subset,const SkBitmap & result,SkResourceCache * localCache)192 bool SkBitmapCache::Add(SkPixelRef* pr, const SkIRect& subset, const SkBitmap& result,
193                         SkResourceCache* localCache) {
194     SkASSERT(result.isImmutable());
195 
196     if (subset.isEmpty()
197         || subset.top() < 0
198         || subset.left() < 0
199         || result.width() != subset.width()
200         || result.height() != subset.height()) {
201         return false;
202     } else {
203         BitmapRec* rec = new BitmapRec(pr->getGenerationID(), 1, 1, subset, result);
204 
205         CHECK_LOCAL(localCache, add, Add, rec);
206         pr->notifyAddedToCache();
207         return true;
208     }
209 }
210 
Find(uint32_t genID,SkBitmap * result,SkResourceCache * localCache)211 bool SkBitmapCache::Find(uint32_t genID, SkBitmap* result, SkResourceCache* localCache) {
212     BitmapKey key(genID, SK_Scalar1, SK_Scalar1, SkIRect::MakeEmpty());
213 
214     return CHECK_LOCAL(localCache, find, Find, key, BitmapRec::Finder, result);
215 }
216 
Add(uint32_t genID,const SkBitmap & result,SkResourceCache * localCache)217 void SkBitmapCache::Add(uint32_t genID, const SkBitmap& result, SkResourceCache* localCache) {
218     SkASSERT(result.isImmutable());
219 
220     BitmapRec* rec = new BitmapRec(genID, 1, 1, SkIRect::MakeEmpty(), result);
221 
222     CHECK_LOCAL(localCache, add, Add, rec);
223 }
224 
225 //////////////////////////////////////////////////////////////////////////////////////////
226 //////////////////////////////////////////////////////////////////////////////////////////
227 
228 namespace {
229 static unsigned gMipMapKeyNamespaceLabel;
230 
231 struct MipMapKey : public SkResourceCache::Key {
232 public:
MipMapKey__anonac8b11c30211::MipMapKey233     MipMapKey(uint32_t genID, const SkIRect& bounds) : fGenID(genID), fBounds(bounds) {
234         this->init(&gMipMapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(genID),
235                    sizeof(fGenID) + sizeof(fBounds));
236     }
237 
238     uint32_t    fGenID;
239     SkIRect     fBounds;
240 };
241 
242 struct MipMapRec : public SkResourceCache::Rec {
MipMapRec__anonac8b11c30211::MipMapRec243     MipMapRec(const SkBitmap& src, const SkMipMap* result)
244         : fKey(src.getGenerationID(), get_bounds_from_bitmap(src))
245         , fMipMap(result)
246     {
247         fMipMap->attachToCacheAndRef();
248     }
249 
~MipMapRec__anonac8b11c30211::MipMapRec250     virtual ~MipMapRec() {
251         fMipMap->detachFromCacheAndUnref();
252     }
253 
getKey__anonac8b11c30211::MipMapRec254     const Key& getKey() const override { return fKey; }
bytesUsed__anonac8b11c30211::MipMapRec255     size_t bytesUsed() const override { return sizeof(fKey) + fMipMap->size(); }
getCategory__anonac8b11c30211::MipMapRec256     const char* getCategory() const override { return "mipmap"; }
diagnostic_only_getDiscardable__anonac8b11c30211::MipMapRec257     SkDiscardableMemory* diagnostic_only_getDiscardable() const override {
258         return fMipMap->diagnostic_only_getDiscardable();
259     }
260 
Finder__anonac8b11c30211::MipMapRec261     static bool Finder(const SkResourceCache::Rec& baseRec, void* contextMip) {
262         const MipMapRec& rec = static_cast<const MipMapRec&>(baseRec);
263         const SkMipMap* mm = SkRef(rec.fMipMap);
264         // the call to ref() above triggers a "lock" in the case of discardable memory,
265         // which means we can now check for null (in case the lock failed).
266         if (nullptr == mm->data()) {
267             mm->unref();    // balance our call to ref()
268             return false;
269         }
270         // the call must call unref() when they are done.
271         *(const SkMipMap**)contextMip = mm;
272         return true;
273     }
274 
275 private:
276     MipMapKey       fKey;
277     const SkMipMap* fMipMap;
278 };
279 }
280 
FindAndRef(const SkBitmapCacheDesc & desc,SkResourceCache * localCache)281 const SkMipMap* SkMipMapCache::FindAndRef(const SkBitmapCacheDesc& desc,
282                                           SkResourceCache* localCache) {
283     // Note: we ignore width/height from desc, just need id and bounds
284     MipMapKey key(desc.fImageID, desc.fBounds);
285     const SkMipMap* result;
286 
287     if (!CHECK_LOCAL(localCache, find, Find, key, MipMapRec::Finder, &result)) {
288         result = nullptr;
289     }
290     return result;
291 }
292 
get_fact(SkResourceCache * localCache)293 static SkResourceCache::DiscardableFactory get_fact(SkResourceCache* localCache) {
294     return localCache ? localCache->GetDiscardableFactory()
295                       : SkResourceCache::GetDiscardableFactory();
296 }
297 
AddAndRef(const SkBitmap & src,SkResourceCache * localCache)298 const SkMipMap* SkMipMapCache::AddAndRef(const SkBitmap& src, SkResourceCache* localCache) {
299     SkMipMap* mipmap = SkMipMap::Build(src, get_fact(localCache));
300     if (mipmap) {
301         MipMapRec* rec = new MipMapRec(src, mipmap);
302         CHECK_LOCAL(localCache, add, Add, rec);
303         src.pixelRef()->notifyAddedToCache();
304     }
305     return mipmap;
306 }
307