blob: b8767644a25f3aa1c51b838dd052a73f897617b0 [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
reed04617132014-08-21 09:46:49 -070029/**
30 This function finds the bounds of the bitmap *within its pixelRef*.
31 If the bitmap lacks a pixelRef, it will return an empty rect, since
32 that doesn't make sense. This may be a useful enough function that
33 it should be somewhere else (in SkBitmap?).
34 */
35static SkIRect get_bounds_from_bitmap(const SkBitmap& bm) {
36 if (!(bm.pixelRef())) {
37 return SkIRect::MakeEmpty();
38 }
39 SkIPoint origin = bm.pixelRefOrigin();
40 return SkIRect::MakeXYWH(origin.fX, origin.fY, bm.width(), bm.height());
41}
42
reed98ed7b62015-09-15 12:38:12 -070043/**
44 * This function finds the bounds of the image. Today this is just the entire bounds,
45 * but in the future we may support subsets within an image, in which case this should
46 * return that subset (see get_bounds_from_bitmap).
47 */
48static SkIRect get_bounds_from_image(const SkImage* image) {
Mike Reed5fa3d6d2017-03-25 09:51:00 -040049 SkASSERT(image->width() > 0 && image->height() > 0);
reed98ed7b62015-09-15 12:38:12 -070050 return SkIRect::MakeWH(image->width(), image->height());
51}
52
Mike Reed5fa3d6d2017-03-25 09:51:00 -040053SkBitmapCacheDesc SkBitmapCacheDesc::Make(uint32_t imageID, int origWidth, int origHeight) {
54 SkASSERT(imageID);
55 SkASSERT(origWidth > 0 && origHeight > 0);
56 return { imageID, 0, 0, {0, 0, origWidth, origHeight} };
57}
58
59SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkBitmap& bm, int scaledWidth, int scaledHeight) {
60 SkASSERT(bm.width() > 0 && bm.height() > 0);
61 SkASSERT(scaledWidth > 0 && scaledHeight > 0);
62 SkASSERT(scaledWidth != bm.width() || scaledHeight != bm.height());
63
64 return { bm.getGenerationID(), scaledWidth, scaledHeight, get_bounds_from_bitmap(bm) };
reed98ed7b62015-09-15 12:38:12 -070065}
66
67SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkBitmap& bm) {
Mike Reed5fa3d6d2017-03-25 09:51:00 -040068 SkASSERT(bm.width() > 0 && bm.height() > 0);
69 SkASSERT(bm.pixelRefOrigin() == SkIPoint::Make(0, 0));
70
71 return { bm.getGenerationID(), 0, 0, get_bounds_from_bitmap(bm) };
reed98ed7b62015-09-15 12:38:12 -070072}
73
Mike Reed5fa3d6d2017-03-25 09:51:00 -040074SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkImage* image, int scaledWidth, int scaledHeight) {
75 SkASSERT(image->width() > 0 && image->height() > 0);
76 SkASSERT(scaledWidth > 0 && scaledHeight > 0);
77
78 // If the dimensions are the same, should we set them to 0,0?
79 //SkASSERT(scaledWidth != image->width() || scaledHeight != image->height());
80
81 return { image->uniqueID(), scaledWidth, scaledHeight, get_bounds_from_image(image) };
reed98ed7b62015-09-15 12:38:12 -070082}
83
84SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkImage* image) {
Mike Reed5fa3d6d2017-03-25 09:51:00 -040085 SkASSERT(image->width() > 0 && image->height() > 0);
86
87 return { image->uniqueID(), 0, 0, get_bounds_from_image(image) };
reed98ed7b62015-09-15 12:38:12 -070088}
89
fmalita171e5b72014-10-22 11:20:40 -070090namespace {
91static unsigned gBitmapKeyNamespaceLabel;
92
reed011f39a2014-08-28 13:35:23 -070093struct BitmapKey : public SkResourceCache::Key {
reed04617132014-08-21 09:46:49 -070094public:
Mike Reedd3a2af72016-11-07 14:30:00 -050095 BitmapKey(const SkBitmapCacheDesc& desc) : fDesc(desc) {
96 this->init(&gBitmapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(fDesc.fImageID),
97 sizeof(fDesc));
reed04617132014-08-21 09:46:49 -070098 }
qiankun.miao045bb7f2014-08-25 06:08:25 -070099
reed995b4bd2015-09-14 10:27:57 -0700100 void dump() const {
Mike Reed5fa3d6d2017-03-25 09:51:00 -0400101 SkDebugf("-- add [%d %d] %d [%d %d %d %d]\n",
102 fDesc.fScaledWidth, fDesc.fScaledHeight, fDesc.fImageID,
103 fDesc.fSubset.x(), fDesc.fSubset.y(), fDesc.fSubset.width(), fDesc.fSubset.height());
reed995b4bd2015-09-14 10:27:57 -0700104 }
105
Mike Reedd3a2af72016-11-07 14:30:00 -0500106 const SkBitmapCacheDesc fDesc;
reed04617132014-08-21 09:46:49 -0700107};
Mike Reed7a542c52017-04-11 12:03:44 -0400108}
reed04617132014-08-21 09:46:49 -0700109
Mike Reed7a542c52017-04-11 12:03:44 -0400110//////////////////////
111#include "SkDiscardableMemory.h"
112#include "SkNextID.h"
113
114void SkBitmapCache_setImmutableWithID(SkPixelRef* pr, uint32_t id) {
115 pr->setImmutableWithID(id);
116}
117
118//#define REC_TRACE SkDebugf
119static void REC_TRACE(const char format[], ...) {}
120
121// for diagnostics
122static int32_t gRecCounter;
123
124class SkBitmapCache::Rec : public SkResourceCache::Rec {
125public:
126 Rec(const SkBitmapCacheDesc& desc, const SkImageInfo& info, size_t rowBytes,
127 std::unique_ptr<SkDiscardableMemory> dm, void* block)
reed98ed7b62015-09-15 12:38:12 -0700128 : fKey(desc)
Mike Reed7a542c52017-04-11 12:03:44 -0400129 , fDM(std::move(dm))
130 , fMalloc(block)
131 , fInfo(info)
132 , fRowBytes(rowBytes)
133 , fExternalCounter(kBeforeFirstInstall_ExternalCounter)
reed98ed7b62015-09-15 12:38:12 -0700134 {
Mike Reed7a542c52017-04-11 12:03:44 -0400135 SkASSERT(!(fDM && fMalloc)); // can't have both
136
137 // We need an ID to return with the bitmap/pixelref.
138 // If they are not scaling, we can return the same ID as the key/desc
139 // If they are scaling, we need a new ID
140 if (desc.fScaledWidth == 0 && desc.fScaledHeight == 0) {
141 fPrUniqueID = desc.fImageID;
142 } else {
143 fPrUniqueID = SkNextID::ImageID();
144 }
145 REC_TRACE(" Rec(%d): [%d %d] %d\n",
146 sk_atomic_inc(&gRecCounter), fInfo.width(), fInfo.height(), fPrUniqueID);
147 }
148
149 ~Rec() override {
150 SkASSERT(0 == fExternalCounter || kBeforeFirstInstall_ExternalCounter == fExternalCounter);
151 if (fDM && kBeforeFirstInstall_ExternalCounter == fExternalCounter) {
152 // we never installed, so we need to unlock before we destroy the DM
153 SkASSERT(fDM->data());
154 fDM->unlock();
155 }
156 REC_TRACE("~Rec(%d): [%d %d] %d\n",
157 sk_atomic_dec(&gRecCounter) - 1, fInfo.width(), fInfo.height(), fPrUniqueID);
158 sk_free(fMalloc); // may be null
reed98ed7b62015-09-15 12:38:12 -0700159 }
160
mtklein36352bf2015-03-25 18:17:31 -0700161 const Key& getKey() const override { return fKey; }
Mike Reed7a542c52017-04-11 12:03:44 -0400162 size_t bytesUsed() const override {
Mike Reed5a2e50e2017-10-02 13:44:11 +0000163 return sizeof(fKey) + fInfo.getSafeSize(fRowBytes);
Mike Reed7a542c52017-04-11 12:03:44 -0400164 }
165 bool canBePurged() override {
166 SkAutoMutexAcquire ama(fMutex);
167 return fExternalCounter == 0;
168 }
169 void postAddInstall(void* payload) override {
170 SkAssertResult(this->install(static_cast<SkBitmap*>(payload)));
171 }
reed680fb9e2014-08-26 09:08:04 -0700172
reed216b6432015-08-19 12:25:40 -0700173 const char* getCategory() const override { return "bitmap"; }
174 SkDiscardableMemory* diagnostic_only_getDiscardable() const override {
Mike Reed7a542c52017-04-11 12:03:44 -0400175 return fDM.get();
176 }
177
178 static void ReleaseProc(void* addr, void* ctx) {
179 Rec* rec = static_cast<Rec*>(ctx);
180 SkAutoMutexAcquire ama(rec->fMutex);
181
182 REC_TRACE(" Rec: [%d] releaseproc\n", rec->fPrUniqueID);
183
184 SkASSERT(rec->fExternalCounter > 0);
185 rec->fExternalCounter -= 1;
186 if (rec->fDM) {
187 SkASSERT(rec->fMalloc == nullptr);
188 if (rec->fExternalCounter == 0) {
189 REC_TRACE(" Rec [%d] unlock\n", rec->fPrUniqueID);
190 rec->fDM->unlock();
191 }
192 } else {
193 SkASSERT(rec->fMalloc != nullptr);
194 }
195 }
196
197 bool install(SkBitmap* bitmap) {
198 SkAutoMutexAcquire ama(fMutex);
199
200 // are we still valid
201 if (!fDM && !fMalloc) {
202 REC_TRACE(" Rec: [%d] invalid\n", fPrUniqueID);
203 return false;
204 }
205
206 /*
207 constructor fExternalCount < 0 fDM->data()
208 after install fExternalCount > 0 fDM->data()
209 after Release fExternalCount == 0 !fDM->data()
210 */
211 if (fDM) {
212 if (kBeforeFirstInstall_ExternalCounter == fExternalCounter) {
213 SkASSERT(fDM->data());
214 } else if (fExternalCounter > 0) {
215 SkASSERT(fDM->data());
216 } else {
217 SkASSERT(fExternalCounter == 0);
218 if (!fDM->lock()) {
219 REC_TRACE(" Rec [%d] re-lock failed\n", fPrUniqueID);
220 fDM.reset(nullptr);
221 return false;
222 }
223 REC_TRACE(" Rec [%d] re-lock succeeded\n", fPrUniqueID);
224 }
225 SkASSERT(fDM->data());
226 }
227
Mike Reed086a4272017-07-18 10:53:11 -0400228 bitmap->installPixels(fInfo, fDM ? fDM->data() : fMalloc, fRowBytes, ReleaseProc, this);
Mike Reed7a542c52017-04-11 12:03:44 -0400229 SkBitmapCache_setImmutableWithID(bitmap->pixelRef(), fPrUniqueID);
230
231 REC_TRACE(" Rec: [%d] install new pr\n", fPrUniqueID);
232
233 if (kBeforeFirstInstall_ExternalCounter == fExternalCounter) {
234 fExternalCounter = 1;
235 } else {
236 fExternalCounter += 1;
237 }
238 SkASSERT(fExternalCounter > 0);
239 return true;
reed216b6432015-08-19 12:25:40 -0700240 }
241
reed7eeba252015-02-24 13:54:23 -0800242 static bool Finder(const SkResourceCache::Rec& baseRec, void* contextBitmap) {
Mike Reed7a542c52017-04-11 12:03:44 -0400243 Rec* rec = (Rec*)&baseRec;
reedc90e0142014-09-15 11:39:44 -0700244 SkBitmap* result = (SkBitmap*)contextBitmap;
Mike Reed7a542c52017-04-11 12:03:44 -0400245 REC_TRACE(" Rec: [%d] found\n", rec->fPrUniqueID);
246 return rec->install(result);
reed595aa052014-09-15 10:15:18 -0700247 }
reed7eeba252015-02-24 13:54:23 -0800248
249private:
250 BitmapKey fKey;
Mike Reed7a542c52017-04-11 12:03:44 -0400251
252 SkMutex fMutex;
253
254 // either fDM or fMalloc can be non-null, but not both
255 std::unique_ptr<SkDiscardableMemory> fDM;
256 void* fMalloc;
257
258 SkImageInfo fInfo;
259 size_t fRowBytes;
260 uint32_t fPrUniqueID;
261
262 // This field counts the number of external pixelrefs we have created. They notify us when
263 // they are destroyed so we can decrement this.
264 //
265 // > 0 we have outstanding pixelrefs
266 // == 0 we have no outstanding pixelrefs, and can be safely purged
267 // < 0 we have been created, but not yet "installed" the first time.
268 //
269 int fExternalCounter;
270
271 enum {
272 kBeforeFirstInstall_ExternalCounter = -1
273 };
reedc90e0142014-09-15 11:39:44 -0700274};
Mike Reed7a542c52017-04-11 12:03:44 -0400275
276void SkBitmapCache::PrivateDeleteRec(Rec* rec) { delete rec; }
277
278SkBitmapCache::RecPtr SkBitmapCache::Alloc(const SkBitmapCacheDesc& desc, const SkImageInfo& info,
279 SkPixmap* pmap) {
280 // Ensure that the caller is self-consistent:
281 // - if they are scaling, the info matches the scaled size
282 // - if they are not, the info matches the subset (i.e. the subset is the entire image)
283 if (desc.fScaledWidth == 0 && desc.fScaledHeight == 0) {
284 SkASSERT(info.width() == desc.fSubset.width());
285 SkASSERT(info.height() == desc.fSubset.height());
286 } else {
287 SkASSERT(info.width() == desc.fScaledWidth);
288 SkASSERT(info.height() == desc.fScaledHeight);
289 }
290
291 const size_t rb = info.minRowBytes();
Mike Reed5a2e50e2017-10-02 13:44:11 +0000292 size_t size = info.getSafeSize(rb);
Mike Reed7a542c52017-04-11 12:03:44 -0400293 if (0 == size) {
294 return nullptr;
295 }
296
297 std::unique_ptr<SkDiscardableMemory> dm;
298 void* block = nullptr;
299
300 auto factory = SkResourceCache::GetDiscardableFactory();
301 if (factory) {
302 dm.reset(factory(size));
303 } else {
304 block = sk_malloc_flags(size, 0);
305 }
306 if (!dm && !block) {
307 return nullptr;
308 }
309 *pmap = SkPixmap(info, dm ? dm->data() : block, rb);
310 return RecPtr(new Rec(desc, info, rb, std::move(dm), block));
311}
312
313void SkBitmapCache::Add(RecPtr rec, SkBitmap* bitmap) {
314 SkResourceCache::Add(rec.release(), bitmap);
315}
316
317bool SkBitmapCache::Find(const SkBitmapCacheDesc& desc, SkBitmap* result) {
318 desc.validate();
319 return SkResourceCache::Find(BitmapKey(desc), SkBitmapCache::Rec::Finder, result);
320}
321
322//////////////////////////////////////////////////////////////////////////////////////////
323//////////////////////////////////////////////////////////////////////////////////////////
reed595aa052014-09-15 10:15:18 -0700324
reed30ad5302014-09-16 10:39:55 -0700325#define CHECK_LOCAL(localCache, localName, globalName, ...) \
reed9d93c2e2014-10-08 05:17:12 -0700326 ((localCache) ? localCache->localName(__VA_ARGS__) : SkResourceCache::globalName(__VA_ARGS__))
reed30ad5302014-09-16 10:39:55 -0700327
reed7eeba252015-02-24 13:54:23 -0800328namespace {
329static unsigned gMipMapKeyNamespaceLabel;
330
331struct MipMapKey : public SkResourceCache::Key {
332public:
Mike Reed5fa3d6d2017-03-25 09:51:00 -0400333 MipMapKey(uint32_t imageID, const SkIRect& subset, SkDestinationSurfaceColorMode colorMode)
334 : fImageID(imageID)
335 , fColorMode(static_cast<uint32_t>(colorMode))
336 , fSubset(subset)
reed6644d932016-06-10 11:41:47 -0700337 {
Mike Reed5fa3d6d2017-03-25 09:51:00 -0400338 SkASSERT(fImageID);
339 SkASSERT(!subset.isEmpty());
340 this->init(&gMipMapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(fImageID),
341 sizeof(fImageID) + sizeof(fColorMode) + sizeof(fSubset));
reed7eeba252015-02-24 13:54:23 -0800342 }
343
Mike Reed5fa3d6d2017-03-25 09:51:00 -0400344 uint32_t fImageID;
Brian Osman7b8400d2016-11-08 17:08:54 -0500345 uint32_t fColorMode;
Mike Reed5fa3d6d2017-03-25 09:51:00 -0400346 SkIRect fSubset;
reed7eeba252015-02-24 13:54:23 -0800347};
reed04617132014-08-21 09:46:49 -0700348
reed011f39a2014-08-28 13:35:23 -0700349struct MipMapRec : public SkResourceCache::Rec {
Mike Reed5fa3d6d2017-03-25 09:51:00 -0400350 MipMapRec(uint32_t imageID, const SkIRect& subset, SkDestinationSurfaceColorMode colorMode,
351 const SkMipMap* result)
352 : fKey(imageID, subset, colorMode)
reed9d93c2e2014-10-08 05:17:12 -0700353 , fMipMap(result)
354 {
355 fMipMap->attachToCacheAndRef();
reed92561a02014-10-02 13:47:08 -0700356 }
piotaixr42b0dfe2014-09-03 11:33:13 -0700357
Brian Salomond3b65972017-03-22 12:05:03 -0400358 ~MipMapRec() override {
reed9d93c2e2014-10-08 05:17:12 -0700359 fMipMap->detachFromCacheAndUnref();
360 }
reed37c5a812014-10-03 13:23:30 -0700361
mtklein36352bf2015-03-25 18:17:31 -0700362 const Key& getKey() const override { return fKey; }
363 size_t bytesUsed() const override { return sizeof(fKey) + fMipMap->size(); }
reed216b6432015-08-19 12:25:40 -0700364 const char* getCategory() const override { return "mipmap"; }
365 SkDiscardableMemory* diagnostic_only_getDiscardable() const override {
366 return fMipMap->diagnostic_only_getDiscardable();
367 }
reed680fb9e2014-08-26 09:08:04 -0700368
reed7eeba252015-02-24 13:54:23 -0800369 static bool Finder(const SkResourceCache::Rec& baseRec, void* contextMip) {
reedc90e0142014-09-15 11:39:44 -0700370 const MipMapRec& rec = static_cast<const MipMapRec&>(baseRec);
reed9d93c2e2014-10-08 05:17:12 -0700371 const SkMipMap* mm = SkRef(rec.fMipMap);
372 // the call to ref() above triggers a "lock" in the case of discardable memory,
373 // which means we can now check for null (in case the lock failed).
halcanary96fcdcc2015-08-27 07:41:13 -0700374 if (nullptr == mm->data()) {
reed9d93c2e2014-10-08 05:17:12 -0700375 mm->unref(); // balance our call to ref()
376 return false;
377 }
378 // the call must call unref() when they are done.
379 *(const SkMipMap**)contextMip = mm;
reedc90e0142014-09-15 11:39:44 -0700380 return true;
381 }
reed9d93c2e2014-10-08 05:17:12 -0700382
383private:
reed7eeba252015-02-24 13:54:23 -0800384 MipMapKey fKey;
reed9d93c2e2014-10-08 05:17:12 -0700385 const SkMipMap* fMipMap;
reedc90e0142014-09-15 11:39:44 -0700386};
reed7eeba252015-02-24 13:54:23 -0800387}
reed595aa052014-09-15 10:15:18 -0700388
reed98ed7b62015-09-15 12:38:12 -0700389const SkMipMap* SkMipMapCache::FindAndRef(const SkBitmapCacheDesc& desc,
Brian Osman7b8400d2016-11-08 17:08:54 -0500390 SkDestinationSurfaceColorMode colorMode,
reed98ed7b62015-09-15 12:38:12 -0700391 SkResourceCache* localCache) {
Mike Reed5fa3d6d2017-03-25 09:51:00 -0400392 SkASSERT(desc.fScaledWidth == 0);
393 SkASSERT(desc.fScaledHeight == 0);
394 MipMapKey key(desc.fImageID, desc.fSubset, colorMode);
reedc90e0142014-09-15 11:39:44 -0700395 const SkMipMap* result;
reed9d93c2e2014-10-08 05:17:12 -0700396
reed7eeba252015-02-24 13:54:23 -0800397 if (!CHECK_LOCAL(localCache, find, Find, key, MipMapRec::Finder, &result)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700398 result = nullptr;
reed680fb9e2014-08-26 09:08:04 -0700399 }
400 return result;
reed04617132014-08-21 09:46:49 -0700401}
402
reed9d93c2e2014-10-08 05:17:12 -0700403static SkResourceCache::DiscardableFactory get_fact(SkResourceCache* localCache) {
404 return localCache ? localCache->GetDiscardableFactory()
405 : SkResourceCache::GetDiscardableFactory();
406}
407
Brian Osman7b8400d2016-11-08 17:08:54 -0500408const SkMipMap* SkMipMapCache::AddAndRef(const SkBitmap& src,
409 SkDestinationSurfaceColorMode colorMode,
reed6644d932016-06-10 11:41:47 -0700410 SkResourceCache* localCache) {
Brian Osman7b8400d2016-11-08 17:08:54 -0500411 SkMipMap* mipmap = SkMipMap::Build(src, colorMode, get_fact(localCache));
reed9d93c2e2014-10-08 05:17:12 -0700412 if (mipmap) {
Mike Reed5fa3d6d2017-03-25 09:51:00 -0400413 MipMapRec* rec = new MipMapRec(src.getGenerationID(), get_bounds_from_bitmap(src),
414 colorMode, mipmap);
reed9d93c2e2014-10-08 05:17:12 -0700415 CHECK_LOCAL(localCache, add, Add, rec);
reed83787d02015-02-25 07:17:11 -0800416 src.pixelRef()->notifyAddedToCache();
reed680fb9e2014-08-26 09:08:04 -0700417 }
reed9d93c2e2014-10-08 05:17:12 -0700418 return mipmap;
reed04617132014-08-21 09:46:49 -0700419}