• 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 
29 /**
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  */
get_bounds_from_bitmap(const SkBitmap & bm)35 static 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 
43 /**
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  */
get_bounds_from_image(const SkImage * image)48 static SkIRect get_bounds_from_image(const SkImage* image) {
49     SkASSERT(image->width() > 0 && image->height() > 0);
50     return SkIRect::MakeWH(image->width(), image->height());
51 }
52 
Make(uint32_t imageID,int origWidth,int origHeight)53 SkBitmapCacheDesc 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 
Make(const SkBitmap & bm,int scaledWidth,int scaledHeight)59 SkBitmapCacheDesc 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) };
65 }
66 
Make(const SkBitmap & bm)67 SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkBitmap& bm) {
68     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) };
72 }
73 
Make(const SkImage * image,int scaledWidth,int scaledHeight)74 SkBitmapCacheDesc 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) };
82 }
83 
Make(const SkImage * image)84 SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkImage* image) {
85     SkASSERT(image->width() > 0 && image->height() > 0);
86 
87     return { image->uniqueID(), 0, 0, get_bounds_from_image(image) };
88 }
89 
90 namespace {
91 static unsigned gBitmapKeyNamespaceLabel;
92 
93 struct BitmapKey : public SkResourceCache::Key {
94 public:
BitmapKey__anon83d4746b0111::BitmapKey95     BitmapKey(const SkBitmapCacheDesc& desc) : fDesc(desc) {
96         this->init(&gBitmapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(fDesc.fImageID),
97                    sizeof(fDesc));
98     }
99 
dump__anon83d4746b0111::BitmapKey100     void dump() const {
101         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());
104     }
105 
106     const SkBitmapCacheDesc fDesc;
107 };
108 }
109 
110 //////////////////////
111 #include "SkDiscardableMemory.h"
112 #include "SkNextID.h"
113 
SkBitmapCache_setImmutableWithID(SkPixelRef * pr,uint32_t id)114 void SkBitmapCache_setImmutableWithID(SkPixelRef* pr, uint32_t id) {
115     pr->setImmutableWithID(id);
116 }
117 
118 //#define REC_TRACE   SkDebugf
REC_TRACE(const char format[],...)119 static void REC_TRACE(const char format[], ...) {}
120 
121 // for diagnostics
122 static int32_t gRecCounter;
123 
124 class SkBitmapCache::Rec : public SkResourceCache::Rec {
125 public:
Rec(const SkBitmapCacheDesc & desc,const SkImageInfo & info,size_t rowBytes,std::unique_ptr<SkDiscardableMemory> dm,void * block)126     Rec(const SkBitmapCacheDesc& desc, const SkImageInfo& info, size_t rowBytes,
127         std::unique_ptr<SkDiscardableMemory> dm, void* block)
128         : fKey(desc)
129         , fDM(std::move(dm))
130         , fMalloc(block)
131         , fInfo(info)
132         , fRowBytes(rowBytes)
133         , fExternalCounter(kBeforeFirstInstall_ExternalCounter)
134     {
135         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 
~Rec()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
159     }
160 
getKey() const161     const Key& getKey() const override { return fKey; }
bytesUsed() const162     size_t bytesUsed() const override {
163         return sizeof(fKey) + fInfo.computeByteSize(fRowBytes);
164     }
canBePurged()165     bool canBePurged() override {
166         SkAutoMutexAcquire ama(fMutex);
167         return fExternalCounter == 0;
168     }
postAddInstall(void * payload)169     void postAddInstall(void* payload) override {
170         SkAssertResult(this->install(static_cast<SkBitmap*>(payload)));
171     }
172 
getCategory() const173     const char* getCategory() const override { return "bitmap"; }
diagnostic_only_getDiscardable() const174     SkDiscardableMemory* diagnostic_only_getDiscardable() const override {
175         return fDM.get();
176     }
177 
ReleaseProc(void * addr,void * ctx)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 
install(SkBitmap * bitmap)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 
228         bitmap->installPixels(fInfo, fDM ? fDM->data() : fMalloc, fRowBytes, ReleaseProc, this);
229         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;
240     }
241 
Finder(const SkResourceCache::Rec & baseRec,void * contextBitmap)242     static bool Finder(const SkResourceCache::Rec& baseRec, void* contextBitmap) {
243         Rec* rec = (Rec*)&baseRec;
244         SkBitmap* result = (SkBitmap*)contextBitmap;
245         REC_TRACE(" Rec: [%d] found\n", rec->fPrUniqueID);
246         return rec->install(result);
247     }
248 
249 private:
250     BitmapKey   fKey;
251 
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     };
274 };
275 
PrivateDeleteRec(Rec * rec)276 void SkBitmapCache::PrivateDeleteRec(Rec* rec) { delete rec; }
277 
Alloc(const SkBitmapCacheDesc & desc,const SkImageInfo & info,SkPixmap * pmap)278 SkBitmapCache::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();
292     size_t size = info.computeByteSize(rb);
293     if (SkImageInfo::ByteSizeOverflowed(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_canfail(size);
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 
Add(RecPtr rec,SkBitmap * bitmap)313 void SkBitmapCache::Add(RecPtr rec, SkBitmap* bitmap) {
314     SkResourceCache::Add(rec.release(), bitmap);
315 }
316 
Find(const SkBitmapCacheDesc & desc,SkBitmap * result)317 bool SkBitmapCache::Find(const SkBitmapCacheDesc& desc, SkBitmap* result) {
318     desc.validate();
319     return SkResourceCache::Find(BitmapKey(desc), SkBitmapCache::Rec::Finder, result);
320 }
321 
322 //////////////////////////////////////////////////////////////////////////////////////////
323 //////////////////////////////////////////////////////////////////////////////////////////
324 
325 #define CHECK_LOCAL(localCache, localName, globalName, ...) \
326     ((localCache) ? localCache->localName(__VA_ARGS__) : SkResourceCache::globalName(__VA_ARGS__))
327 
328 namespace {
329 static unsigned gMipMapKeyNamespaceLabel;
330 
331 struct MipMapKey : public SkResourceCache::Key {
332 public:
MipMapKey__anon83d4746b0311::MipMapKey333     MipMapKey(uint32_t imageID, const SkIRect& subset, SkDestinationSurfaceColorMode colorMode)
334         : fImageID(imageID)
335         , fColorMode(static_cast<uint32_t>(colorMode))
336         , fSubset(subset)
337     {
338         SkASSERT(fImageID);
339         SkASSERT(!subset.isEmpty());
340         this->init(&gMipMapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(fImageID),
341                    sizeof(fImageID) + sizeof(fColorMode) + sizeof(fSubset));
342     }
343 
344     uint32_t    fImageID;
345     uint32_t    fColorMode;
346     SkIRect     fSubset;
347 };
348 
349 struct MipMapRec : public SkResourceCache::Rec {
MipMapRec__anon83d4746b0311::MipMapRec350     MipMapRec(uint32_t imageID, const SkIRect& subset, SkDestinationSurfaceColorMode colorMode,
351               const SkMipMap* result)
352         : fKey(imageID, subset, colorMode)
353         , fMipMap(result)
354     {
355         fMipMap->attachToCacheAndRef();
356     }
357 
~MipMapRec__anon83d4746b0311::MipMapRec358     ~MipMapRec() override {
359         fMipMap->detachFromCacheAndUnref();
360     }
361 
getKey__anon83d4746b0311::MipMapRec362     const Key& getKey() const override { return fKey; }
bytesUsed__anon83d4746b0311::MipMapRec363     size_t bytesUsed() const override { return sizeof(fKey) + fMipMap->size(); }
getCategory__anon83d4746b0311::MipMapRec364     const char* getCategory() const override { return "mipmap"; }
diagnostic_only_getDiscardable__anon83d4746b0311::MipMapRec365     SkDiscardableMemory* diagnostic_only_getDiscardable() const override {
366         return fMipMap->diagnostic_only_getDiscardable();
367     }
368 
Finder__anon83d4746b0311::MipMapRec369     static bool Finder(const SkResourceCache::Rec& baseRec, void* contextMip) {
370         const MipMapRec& rec = static_cast<const MipMapRec&>(baseRec);
371         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).
374         if (nullptr == mm->data()) {
375             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;
380         return true;
381     }
382 
383 private:
384     MipMapKey       fKey;
385     const SkMipMap* fMipMap;
386 };
387 }
388 
FindAndRef(const SkBitmapCacheDesc & desc,SkDestinationSurfaceColorMode colorMode,SkResourceCache * localCache)389 const SkMipMap* SkMipMapCache::FindAndRef(const SkBitmapCacheDesc& desc,
390                                           SkDestinationSurfaceColorMode colorMode,
391                                           SkResourceCache* localCache) {
392     SkASSERT(desc.fScaledWidth == 0);
393     SkASSERT(desc.fScaledHeight == 0);
394     MipMapKey key(desc.fImageID, desc.fSubset, colorMode);
395     const SkMipMap* result;
396 
397     if (!CHECK_LOCAL(localCache, find, Find, key, MipMapRec::Finder, &result)) {
398         result = nullptr;
399     }
400     return result;
401 }
402 
get_fact(SkResourceCache * localCache)403 static SkResourceCache::DiscardableFactory get_fact(SkResourceCache* localCache) {
404     return localCache ? localCache->GetDiscardableFactory()
405                       : SkResourceCache::GetDiscardableFactory();
406 }
407 
AddAndRef(const SkBitmap & src,SkDestinationSurfaceColorMode colorMode,SkResourceCache * localCache)408 const SkMipMap* SkMipMapCache::AddAndRef(const SkBitmap& src,
409                                          SkDestinationSurfaceColorMode colorMode,
410                                          SkResourceCache* localCache) {
411     SkMipMap* mipmap = SkMipMap::Build(src, colorMode, get_fact(localCache));
412     if (mipmap) {
413         MipMapRec* rec = new MipMapRec(src.getGenerationID(), get_bounds_from_bitmap(src),
414                                        colorMode, mipmap);
415         CHECK_LOCAL(localCache, add, Add, rec);
416         src.pixelRef()->notifyAddedToCache();
417     }
418     return mipmap;
419 }
420