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