blob: 83eec1b666b7e2b56a2cd233f87ff470274e3add [file] [log] [blame]
reed04617132014-08-21 09:46:49 -07001/*
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"
reed98ed7b62015-09-15 12:38:12 -07009#include "SkImage.h"
reed011f39a2014-08-28 13:35:23 -070010#include "SkResourceCache.h"
reed680fb9e2014-08-26 09:08:04 -070011#include "SkMipMap.h"
reed83787d02015-02-25 07:17:11 -080012#include "SkPixelRef.h"
reed04617132014-08-21 09:46:49 -070013#include "SkRect.h"
14
reed7eeba252015-02-24 13:54:23 -080015/**
16 * Use this for bitmapcache and mipmapcache entries.
17 */
18uint64_t SkMakeResourceCacheSharedIDForBitmap(uint32_t bitmapGenID) {
19 uint64_t sharedID = SkSetFourByteTag('b', 'm', 'a', 'p');
20 return (sharedID << 32) | bitmapGenID;
21}
22
23void SkNotifyBitmapGenIDIsStale(uint32_t bitmapGenID) {
24 SkResourceCache::PostPurgeSharedID(SkMakeResourceCacheSharedIDForBitmap(bitmapGenID));
25}
26
27///////////////////////////////////////////////////////////////////////////////////////////////////
28
reed14b6aba2014-08-29 10:25:26 -070029SkBitmap::Allocator* SkBitmapCache::GetAllocator() {
30 return SkResourceCache::GetAllocator();
31}
32
reed04617132014-08-21 09:46:49 -070033/**
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 */
39static 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
reed98ed7b62015-09-15 12:38:12 -070047/**
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 */
52static SkIRect get_bounds_from_image(const SkImage* image) {
53 return SkIRect::MakeWH(image->width(), image->height());
54}
55
56SkBitmapCacheDesc 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
65SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkBitmap& bm) {
66 return Make(bm, bm.width(), bm.height());
67}
68
69SkBitmapCacheDesc 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
78SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkImage* image) {
79 return Make(image, image->width(), image->height());
80}
81
fmalita171e5b72014-10-22 11:20:40 -070082namespace {
83static unsigned gBitmapKeyNamespaceLabel;
84
reed011f39a2014-08-28 13:35:23 -070085struct BitmapKey : public SkResourceCache::Key {
reed04617132014-08-21 09:46:49 -070086public:
reed99138872015-08-31 15:16:17 -070087 BitmapKey(uint32_t genID, int width, int height, const SkIRect& bounds)
reed7eeba252015-02-24 13:54:23 -080088 : fGenID(genID)
reed99138872015-08-31 15:16:17 -070089 , fWidth(width)
90 , fHeight(height)
reed7eeba252015-02-24 13:54:23 -080091 , fBounds(bounds)
reed04617132014-08-21 09:46:49 -070092 {
reed98ed7b62015-09-15 12:38:12 -070093 this->init(&gBitmapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(fGenID),
94 sizeof(fGenID) + sizeof(fWidth) + sizeof(fHeight) + sizeof(fBounds));
95 }
96
97 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),
reed99138872015-08-31 15:16:17 -0700104 sizeof(fGenID) + sizeof(fWidth) + sizeof(fHeight) + sizeof(fBounds));
reed04617132014-08-21 09:46:49 -0700105 }
qiankun.miao045bb7f2014-08-25 06:08:25 -0700106
reed995b4bd2015-09-14 10:27:57 -0700107 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
reed99138872015-08-31 15:16:17 -0700112 const uint32_t fGenID;
113 const int fWidth;
114 const int fHeight;
115 const SkIRect fBounds;
reed04617132014-08-21 09:46:49 -0700116};
117
reed011f39a2014-08-28 13:35:23 -0700118struct BitmapRec : public SkResourceCache::Rec {
reed99138872015-08-31 15:16:17 -0700119 BitmapRec(uint32_t genID, int width, int height, const SkIRect& bounds,
reed680fb9e2014-08-26 09:08:04 -0700120 const SkBitmap& result)
reed99138872015-08-31 15:16:17 -0700121 : fKey(genID, width, height, bounds)
reed680fb9e2014-08-26 09:08:04 -0700122 , fBitmap(result)
reed995b4bd2015-09-14 10:27:57 -0700123 {
124#ifdef TRACE_NEW_BITMAP_CACHE_RECS
125 fKey.dump();
126#endif
127 }
reed680fb9e2014-08-26 09:08:04 -0700128
reed98ed7b62015-09-15 12:38:12 -0700129 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
mtklein36352bf2015-03-25 18:17:31 -0700138 const Key& getKey() const override { return fKey; }
139 size_t bytesUsed() const override { return sizeof(fKey) + fBitmap.getSize(); }
reed680fb9e2014-08-26 09:08:04 -0700140
reed216b6432015-08-19 12:25:40 -0700141 const char* getCategory() const override { return "bitmap"; }
142 SkDiscardableMemory* diagnostic_only_getDiscardable() const override {
143 return fBitmap.pixelRef()->diagnostic_only_getDiscardable();
144 }
145
reed7eeba252015-02-24 13:54:23 -0800146 static bool Finder(const SkResourceCache::Rec& baseRec, void* contextBitmap) {
reedc90e0142014-09-15 11:39:44 -0700147 const BitmapRec& rec = static_cast<const BitmapRec&>(baseRec);
148 SkBitmap* result = (SkBitmap*)contextBitmap;
reed595aa052014-09-15 10:15:18 -0700149
reedc90e0142014-09-15 11:39:44 -0700150 *result = rec.fBitmap;
reed595aa052014-09-15 10:15:18 -0700151 result->lockPixels();
reedc90e0142014-09-15 11:39:44 -0700152 return SkToBool(result->getPixels());
reed595aa052014-09-15 10:15:18 -0700153 }
reed7eeba252015-02-24 13:54:23 -0800154
155private:
156 BitmapKey fKey;
157 SkBitmap fBitmap;
reedc90e0142014-09-15 11:39:44 -0700158};
fmalita171e5b72014-10-22 11:20:40 -0700159} // namespace
reed595aa052014-09-15 10:15:18 -0700160
reed30ad5302014-09-16 10:39:55 -0700161#define CHECK_LOCAL(localCache, localName, globalName, ...) \
reed9d93c2e2014-10-08 05:17:12 -0700162 ((localCache) ? localCache->localName(__VA_ARGS__) : SkResourceCache::globalName(__VA_ARGS__))
reed30ad5302014-09-16 10:39:55 -0700163
reed98ed7b62015-09-15 12:38:12 -0700164bool SkBitmapCache::FindWH(const SkBitmapCacheDesc& desc, SkBitmap* result,
reed99138872015-08-31 15:16:17 -0700165 SkResourceCache* localCache) {
reed98ed7b62015-09-15 12:38:12 -0700166 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
173bool SkBitmapCache::AddWH(const SkBitmapCacheDesc& desc, const SkBitmap& result,
174 SkResourceCache* localCache) {
175 if (0 == desc.fWidth || 0 == desc.fHeight) {
reed04617132014-08-21 09:46:49 -0700176 // degenerate, and the key we use for mipmaps
reed680fb9e2014-08-26 09:08:04 -0700177 return false;
reed04617132014-08-21 09:46:49 -0700178 }
reed14b6aba2014-08-29 10:25:26 -0700179 SkASSERT(result.isImmutable());
reed98ed7b62015-09-15 12:38:12 -0700180 BitmapRec* rec = new BitmapRec(desc, result);
reed30ad5302014-09-16 10:39:55 -0700181 CHECK_LOCAL(localCache, add, Add, rec);
reed98ed7b62015-09-15 12:38:12 -0700182 return true;
reed04617132014-08-21 09:46:49 -0700183}
184
reed30ad5302014-09-16 10:39:55 -0700185bool SkBitmapCache::Find(uint32_t genID, const SkIRect& subset, SkBitmap* result,
186 SkResourceCache* localCache) {
piotaixr42b0dfe2014-09-03 11:33:13 -0700187 BitmapKey key(genID, SK_Scalar1, SK_Scalar1, subset);
reed30ad5302014-09-16 10:39:55 -0700188
reed7eeba252015-02-24 13:54:23 -0800189 return CHECK_LOCAL(localCache, find, Find, key, BitmapRec::Finder, result);
reed04617132014-08-21 09:46:49 -0700190}
191
reed83787d02015-02-25 07:17:11 -0800192bool SkBitmapCache::Add(SkPixelRef* pr, const SkIRect& subset, const SkBitmap& result,
reed30ad5302014-09-16 10:39:55 -0700193 SkResourceCache* localCache) {
reed14b6aba2014-08-29 10:25:26 -0700194 SkASSERT(result.isImmutable());
reed04617132014-08-21 09:46:49 -0700195
piotaixr42b0dfe2014-09-03 11:33:13 -0700196 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 {
halcanary385fe4d2015-08-26 13:07:48 -0700203 BitmapRec* rec = new BitmapRec(pr->getGenerationID(), 1, 1, subset, result);
piotaixr42b0dfe2014-09-03 11:33:13 -0700204
reed30ad5302014-09-16 10:39:55 -0700205 CHECK_LOCAL(localCache, add, Add, rec);
reed83787d02015-02-25 07:17:11 -0800206 pr->notifyAddedToCache();
piotaixr42b0dfe2014-09-03 11:33:13 -0700207 return true;
208 }
209}
reed7eeba252015-02-24 13:54:23 -0800210
reed6f1216a2015-08-04 08:10:13 -0700211bool 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
217void SkBitmapCache::Add(uint32_t genID, const SkBitmap& result, SkResourceCache* localCache) {
218 SkASSERT(result.isImmutable());
219
halcanary385fe4d2015-08-26 13:07:48 -0700220 BitmapRec* rec = new BitmapRec(genID, 1, 1, SkIRect::MakeEmpty(), result);
reed6f1216a2015-08-04 08:10:13 -0700221
222 CHECK_LOCAL(localCache, add, Add, rec);
223}
224
reed680fb9e2014-08-26 09:08:04 -0700225//////////////////////////////////////////////////////////////////////////////////////////
reed7eeba252015-02-24 13:54:23 -0800226//////////////////////////////////////////////////////////////////////////////////////////
227
228namespace {
229static unsigned gMipMapKeyNamespaceLabel;
230
231struct MipMapKey : public SkResourceCache::Key {
232public:
233 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};
reed04617132014-08-21 09:46:49 -0700241
reed011f39a2014-08-28 13:35:23 -0700242struct MipMapRec : public SkResourceCache::Rec {
reed680fb9e2014-08-26 09:08:04 -0700243 MipMapRec(const SkBitmap& src, const SkMipMap* result)
reed7eeba252015-02-24 13:54:23 -0800244 : fKey(src.getGenerationID(), get_bounds_from_bitmap(src))
reed9d93c2e2014-10-08 05:17:12 -0700245 , fMipMap(result)
246 {
247 fMipMap->attachToCacheAndRef();
reed92561a02014-10-02 13:47:08 -0700248 }
piotaixr42b0dfe2014-09-03 11:33:13 -0700249
reed9d93c2e2014-10-08 05:17:12 -0700250 virtual ~MipMapRec() {
251 fMipMap->detachFromCacheAndUnref();
252 }
reed37c5a812014-10-03 13:23:30 -0700253
mtklein36352bf2015-03-25 18:17:31 -0700254 const Key& getKey() const override { return fKey; }
255 size_t bytesUsed() const override { return sizeof(fKey) + fMipMap->size(); }
reed216b6432015-08-19 12:25:40 -0700256 const char* getCategory() const override { return "mipmap"; }
257 SkDiscardableMemory* diagnostic_only_getDiscardable() const override {
258 return fMipMap->diagnostic_only_getDiscardable();
259 }
reed680fb9e2014-08-26 09:08:04 -0700260
reed7eeba252015-02-24 13:54:23 -0800261 static bool Finder(const SkResourceCache::Rec& baseRec, void* contextMip) {
reedc90e0142014-09-15 11:39:44 -0700262 const MipMapRec& rec = static_cast<const MipMapRec&>(baseRec);
reed9d93c2e2014-10-08 05:17:12 -0700263 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).
halcanary96fcdcc2015-08-27 07:41:13 -0700266 if (nullptr == mm->data()) {
reed9d93c2e2014-10-08 05:17:12 -0700267 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;
reedc90e0142014-09-15 11:39:44 -0700272 return true;
273 }
reed9d93c2e2014-10-08 05:17:12 -0700274
275private:
reed7eeba252015-02-24 13:54:23 -0800276 MipMapKey fKey;
reed9d93c2e2014-10-08 05:17:12 -0700277 const SkMipMap* fMipMap;
reedc90e0142014-09-15 11:39:44 -0700278};
reed7eeba252015-02-24 13:54:23 -0800279}
reed595aa052014-09-15 10:15:18 -0700280
reed98ed7b62015-09-15 12:38:12 -0700281const 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);
reedc90e0142014-09-15 11:39:44 -0700285 const SkMipMap* result;
reed9d93c2e2014-10-08 05:17:12 -0700286
reed7eeba252015-02-24 13:54:23 -0800287 if (!CHECK_LOCAL(localCache, find, Find, key, MipMapRec::Finder, &result)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700288 result = nullptr;
reed680fb9e2014-08-26 09:08:04 -0700289 }
290 return result;
reed04617132014-08-21 09:46:49 -0700291}
292
reed9d93c2e2014-10-08 05:17:12 -0700293static SkResourceCache::DiscardableFactory get_fact(SkResourceCache* localCache) {
294 return localCache ? localCache->GetDiscardableFactory()
295 : SkResourceCache::GetDiscardableFactory();
296}
297
298const SkMipMap* SkMipMapCache::AddAndRef(const SkBitmap& src, SkResourceCache* localCache) {
299 SkMipMap* mipmap = SkMipMap::Build(src, get_fact(localCache));
300 if (mipmap) {
halcanary385fe4d2015-08-26 13:07:48 -0700301 MipMapRec* rec = new MipMapRec(src, mipmap);
reed9d93c2e2014-10-08 05:17:12 -0700302 CHECK_LOCAL(localCache, add, Add, rec);
reed83787d02015-02-25 07:17:11 -0800303 src.pixelRef()->notifyAddedToCache();
reed680fb9e2014-08-26 09:08:04 -0700304 }
reed9d93c2e2014-10-08 05:17:12 -0700305 return mipmap;
reed04617132014-08-21 09:46:49 -0700306}