blob: 153a24748b81eb4e7c72e2097e12cbed7793fe8b [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:
reed6644d932016-06-10 11:41:47 -0700233 MipMapKey(uint32_t genID, SkSourceGammaTreatment treatment, const SkIRect& bounds)
234 : fGenID(genID), fSrcGammaTreatment(static_cast<uint32_t>(treatment)), fBounds(bounds)
235 {
reed7eeba252015-02-24 13:54:23 -0800236 this->init(&gMipMapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(genID),
reed6644d932016-06-10 11:41:47 -0700237 sizeof(fGenID) + sizeof(fSrcGammaTreatment) + sizeof(fBounds));
reed7eeba252015-02-24 13:54:23 -0800238 }
239
240 uint32_t fGenID;
reed6644d932016-06-10 11:41:47 -0700241 uint32_t fSrcGammaTreatment;
reed7eeba252015-02-24 13:54:23 -0800242 SkIRect fBounds;
243};
reed04617132014-08-21 09:46:49 -0700244
reed011f39a2014-08-28 13:35:23 -0700245struct MipMapRec : public SkResourceCache::Rec {
reed6644d932016-06-10 11:41:47 -0700246 MipMapRec(const SkBitmap& src, SkSourceGammaTreatment treatment, const SkMipMap* result)
247 : fKey(src.getGenerationID(), treatment, get_bounds_from_bitmap(src))
reed9d93c2e2014-10-08 05:17:12 -0700248 , fMipMap(result)
249 {
250 fMipMap->attachToCacheAndRef();
reed92561a02014-10-02 13:47:08 -0700251 }
piotaixr42b0dfe2014-09-03 11:33:13 -0700252
reed9d93c2e2014-10-08 05:17:12 -0700253 virtual ~MipMapRec() {
254 fMipMap->detachFromCacheAndUnref();
255 }
reed37c5a812014-10-03 13:23:30 -0700256
mtklein36352bf2015-03-25 18:17:31 -0700257 const Key& getKey() const override { return fKey; }
258 size_t bytesUsed() const override { return sizeof(fKey) + fMipMap->size(); }
reed216b6432015-08-19 12:25:40 -0700259 const char* getCategory() const override { return "mipmap"; }
260 SkDiscardableMemory* diagnostic_only_getDiscardable() const override {
261 return fMipMap->diagnostic_only_getDiscardable();
262 }
reed680fb9e2014-08-26 09:08:04 -0700263
reed7eeba252015-02-24 13:54:23 -0800264 static bool Finder(const SkResourceCache::Rec& baseRec, void* contextMip) {
reedc90e0142014-09-15 11:39:44 -0700265 const MipMapRec& rec = static_cast<const MipMapRec&>(baseRec);
reed9d93c2e2014-10-08 05:17:12 -0700266 const SkMipMap* mm = SkRef(rec.fMipMap);
267 // the call to ref() above triggers a "lock" in the case of discardable memory,
268 // which means we can now check for null (in case the lock failed).
halcanary96fcdcc2015-08-27 07:41:13 -0700269 if (nullptr == mm->data()) {
reed9d93c2e2014-10-08 05:17:12 -0700270 mm->unref(); // balance our call to ref()
271 return false;
272 }
273 // the call must call unref() when they are done.
274 *(const SkMipMap**)contextMip = mm;
reedc90e0142014-09-15 11:39:44 -0700275 return true;
276 }
reed9d93c2e2014-10-08 05:17:12 -0700277
278private:
reed7eeba252015-02-24 13:54:23 -0800279 MipMapKey fKey;
reed9d93c2e2014-10-08 05:17:12 -0700280 const SkMipMap* fMipMap;
reedc90e0142014-09-15 11:39:44 -0700281};
reed7eeba252015-02-24 13:54:23 -0800282}
reed595aa052014-09-15 10:15:18 -0700283
reed98ed7b62015-09-15 12:38:12 -0700284const SkMipMap* SkMipMapCache::FindAndRef(const SkBitmapCacheDesc& desc,
reed6644d932016-06-10 11:41:47 -0700285 SkSourceGammaTreatment treatment,
reed98ed7b62015-09-15 12:38:12 -0700286 SkResourceCache* localCache) {
287 // Note: we ignore width/height from desc, just need id and bounds
reed6644d932016-06-10 11:41:47 -0700288 MipMapKey key(desc.fImageID, treatment, desc.fBounds);
reedc90e0142014-09-15 11:39:44 -0700289 const SkMipMap* result;
reed9d93c2e2014-10-08 05:17:12 -0700290
reed7eeba252015-02-24 13:54:23 -0800291 if (!CHECK_LOCAL(localCache, find, Find, key, MipMapRec::Finder, &result)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700292 result = nullptr;
reed680fb9e2014-08-26 09:08:04 -0700293 }
294 return result;
reed04617132014-08-21 09:46:49 -0700295}
296
reed9d93c2e2014-10-08 05:17:12 -0700297static SkResourceCache::DiscardableFactory get_fact(SkResourceCache* localCache) {
298 return localCache ? localCache->GetDiscardableFactory()
299 : SkResourceCache::GetDiscardableFactory();
300}
301
reed6644d932016-06-10 11:41:47 -0700302const SkMipMap* SkMipMapCache::AddAndRef(const SkBitmap& src, SkSourceGammaTreatment treatment,
303 SkResourceCache* localCache) {
304 SkMipMap* mipmap = SkMipMap::Build(src, treatment, get_fact(localCache));
reed9d93c2e2014-10-08 05:17:12 -0700305 if (mipmap) {
reed6644d932016-06-10 11:41:47 -0700306 MipMapRec* rec = new MipMapRec(src, treatment, mipmap);
reed9d93c2e2014-10-08 05:17:12 -0700307 CHECK_LOCAL(localCache, add, Add, rec);
reed83787d02015-02-25 07:17:11 -0800308 src.pixelRef()->notifyAddedToCache();
reed680fb9e2014-08-26 09:08:04 -0700309 }
reed9d93c2e2014-10-08 05:17:12 -0700310 return mipmap;
reed04617132014-08-21 09:46:49 -0700311}