• 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 "include/core/SkImage.h"
9 #include "include/core/SkPixelRef.h"
10 #include "include/core/SkRect.h"
11 #include "src/core/SkBitmapCache.h"
12 #include "src/core/SkMipmap.h"
13 #include "src/core/SkResourceCache.h"
14 #include "src/image/SkImage_Base.h"
15 
16 /**
17  *  Use this for bitmapcache and mipmapcache entries.
18  */
SkMakeResourceCacheSharedIDForBitmap(uint32_t bitmapGenID)19 uint64_t SkMakeResourceCacheSharedIDForBitmap(uint32_t bitmapGenID) {
20     uint64_t sharedID = SkSetFourByteTag('b', 'm', 'a', 'p');
21     return (sharedID << 32) | bitmapGenID;
22 }
23 
SkNotifyBitmapGenIDIsStale(uint32_t bitmapGenID)24 void SkNotifyBitmapGenIDIsStale(uint32_t bitmapGenID) {
25     SkResourceCache::PostPurgeSharedID(SkMakeResourceCacheSharedIDForBitmap(bitmapGenID));
26 }
27 
28 ///////////////////////////////////////////////////////////////////////////////////////////////////
29 
Make(uint32_t imageID,const SkIRect & subset)30 SkBitmapCacheDesc SkBitmapCacheDesc::Make(uint32_t imageID, const SkIRect& subset) {
31     SkASSERT(imageID);
32     SkASSERT(subset.width() > 0 && subset.height() > 0);
33     return { imageID, subset };
34 }
35 
Make(const SkImage * image)36 SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkImage* image) {
37     SkIRect bounds = SkIRect::MakeWH(image->width(), image->height());
38     return Make(image->uniqueID(), bounds);
39 }
40 
41 namespace {
42 static unsigned gBitmapKeyNamespaceLabel;
43 
44 struct BitmapKey : public SkResourceCache::Key {
45 public:
BitmapKey__anon1533787c0111::BitmapKey46     BitmapKey(const SkBitmapCacheDesc& desc) : fDesc(desc) {
47         this->init(&gBitmapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(fDesc.fImageID),
48                    sizeof(fDesc));
49     }
50 
51     const SkBitmapCacheDesc fDesc;
52 };
53 }  // namespace
54 
55 //////////////////////
56 #include "include/private/chromium/SkDiscardableMemory.h"
57 #include "src/core/SkNextID.h"
58 
SkBitmapCache_setImmutableWithID(SkPixelRef * pr,uint32_t id)59 void SkBitmapCache_setImmutableWithID(SkPixelRef* pr, uint32_t id) {
60     pr->setImmutableWithID(id);
61 }
62 
63 class SkBitmapCache::Rec : public SkResourceCache::Rec {
64 public:
Rec(const SkBitmapCacheDesc & desc,const SkImageInfo & info,size_t rowBytes,std::unique_ptr<SkDiscardableMemory> dm,void * block)65     Rec(const SkBitmapCacheDesc& desc, const SkImageInfo& info, size_t rowBytes,
66         std::unique_ptr<SkDiscardableMemory> dm, void* block)
67         : fKey(desc)
68         , fDM(std::move(dm))
69         , fMalloc(block)
70         , fInfo(info)
71         , fRowBytes(rowBytes)
72     {
73         SkASSERT(!(fDM && fMalloc));    // can't have both
74 
75         // We need an ID to return with the bitmap/pixelref. We can't necessarily use the key/desc
76         // ID - lazy images cache the same ID with multiple keys (in different color types).
77         fPrUniqueID = SkNextID::ImageID();
78     }
79 
~Rec()80     ~Rec() override {
81         SkASSERT(0 == fExternalCounter);
82         if (fDM && fDiscardableIsLocked) {
83             SkASSERT(fDM->data());
84             fDM->unlock();
85         }
86         sk_free(fMalloc);   // may be null
87     }
88 
getKey() const89     const Key& getKey() const override { return fKey; }
bytesUsed() const90     size_t bytesUsed() const override {
91         return sizeof(fKey) + fInfo.computeByteSize(fRowBytes);
92     }
canBePurged()93     bool canBePurged() override {
94         SkAutoMutexExclusive ama(fMutex);
95         return fExternalCounter == 0;
96     }
postAddInstall(void * payload)97     void postAddInstall(void* payload) override {
98         SkAssertResult(this->install(static_cast<SkBitmap*>(payload)));
99     }
100 
getCategory() const101     const char* getCategory() const override { return "bitmap"; }
diagnostic_only_getDiscardable() const102     SkDiscardableMemory* diagnostic_only_getDiscardable() const override {
103         return fDM.get();
104     }
105 
ReleaseProc(void * addr,void * ctx)106     static void ReleaseProc(void* addr, void* ctx) {
107         Rec* rec = static_cast<Rec*>(ctx);
108         SkAutoMutexExclusive ama(rec->fMutex);
109 
110         SkASSERT(rec->fExternalCounter > 0);
111         rec->fExternalCounter -= 1;
112         if (rec->fDM) {
113             SkASSERT(rec->fMalloc == nullptr);
114             if (rec->fExternalCounter == 0) {
115                 rec->fDM->unlock();
116                 rec->fDiscardableIsLocked = false;
117             }
118         } else {
119             SkASSERT(rec->fMalloc != nullptr);
120         }
121     }
122 
install(SkBitmap * bitmap)123     bool install(SkBitmap* bitmap) {
124         SkAutoMutexExclusive ama(fMutex);
125 
126         if (!fDM && !fMalloc) {
127             return false;
128         }
129 
130         if (fDM) {
131             if (!fDiscardableIsLocked) {
132                 SkASSERT(fExternalCounter == 0);
133                 if (!fDM->lock()) {
134                     fDM.reset(nullptr);
135                     return false;
136                 }
137                 fDiscardableIsLocked = true;
138             }
139             SkASSERT(fDM->data());
140         }
141 
142         bitmap->installPixels(fInfo, fDM ? fDM->data() : fMalloc, fRowBytes, ReleaseProc, this);
143         SkBitmapCache_setImmutableWithID(bitmap->pixelRef(), fPrUniqueID);
144         fExternalCounter++;
145 
146         return true;
147     }
148 
Finder(const SkResourceCache::Rec & baseRec,void * contextBitmap)149     static bool Finder(const SkResourceCache::Rec& baseRec, void* contextBitmap) {
150         Rec* rec = (Rec*)&baseRec;
151         SkBitmap* result = (SkBitmap*)contextBitmap;
152         return rec->install(result);
153     }
154 
155 private:
156     BitmapKey   fKey;
157 
158     SkMutex     fMutex;
159 
160     // either fDM or fMalloc can be non-null, but not both
161     std::unique_ptr<SkDiscardableMemory> fDM;
162     void*       fMalloc;
163 
164     SkImageInfo fInfo;
165     size_t      fRowBytes;
166     uint32_t    fPrUniqueID;
167 
168     // This field counts the number of external pixelrefs we have created.
169     // They notify us when they are destroyed so we can decrement this.
170     int  fExternalCounter     = 0;
171     bool fDiscardableIsLocked = true;
172 };
173 
PrivateDeleteRec(Rec * rec)174 void SkBitmapCache::PrivateDeleteRec(Rec* rec) { delete rec; }
175 
Alloc(const SkBitmapCacheDesc & desc,const SkImageInfo & info,SkPixmap * pmap)176 SkBitmapCache::RecPtr SkBitmapCache::Alloc(const SkBitmapCacheDesc& desc, const SkImageInfo& info,
177                                            SkPixmap* pmap) {
178     // Ensure that the info matches the subset (i.e. the subset is the entire image)
179     SkASSERT(info.width() == desc.fSubset.width());
180     SkASSERT(info.height() == desc.fSubset.height());
181 
182     const size_t rb = info.minRowBytes();
183     size_t size = info.computeByteSize(rb);
184     if (SkImageInfo::ByteSizeOverflowed(size)) {
185         return nullptr;
186     }
187 
188     std::unique_ptr<SkDiscardableMemory> dm;
189     void* block = nullptr;
190 
191     auto factory = SkResourceCache::GetDiscardableFactory();
192     if (factory) {
193         dm.reset(factory(size));
194     } else {
195         block = sk_malloc_canfail(size);
196     }
197     if (!dm && !block) {
198         return nullptr;
199     }
200     *pmap = SkPixmap(info, dm ? dm->data() : block, rb);
201     return RecPtr(new Rec(desc, info, rb, std::move(dm), block));
202 }
203 
Add(RecPtr rec,SkBitmap * bitmap)204 void SkBitmapCache::Add(RecPtr rec, SkBitmap* bitmap) {
205     SkResourceCache::Add(rec.release(), bitmap);
206 }
207 
Find(const SkBitmapCacheDesc & desc,SkBitmap * result)208 bool SkBitmapCache::Find(const SkBitmapCacheDesc& desc, SkBitmap* result) {
209     desc.validate();
210     return SkResourceCache::Find(BitmapKey(desc), SkBitmapCache::Rec::Finder, result);
211 }
212 
213 //////////////////////////////////////////////////////////////////////////////////////////
214 //////////////////////////////////////////////////////////////////////////////////////////
215 
216 #define CHECK_LOCAL(localCache, localName, globalName, ...) \
217     ((localCache) ? localCache->localName(__VA_ARGS__) : SkResourceCache::globalName(__VA_ARGS__))
218 
219 namespace {
220 static unsigned gMipMapKeyNamespaceLabel;
221 
222 struct MipMapKey : public SkResourceCache::Key {
223 public:
MipMapKey__anon1533787c0211::MipMapKey224     MipMapKey(const SkBitmapCacheDesc& desc) : fDesc(desc) {
225         this->init(&gMipMapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(fDesc.fImageID),
226                    sizeof(fDesc));
227     }
228 
229     const SkBitmapCacheDesc fDesc;
230 };
231 
232 struct MipMapRec : public SkResourceCache::Rec {
MipMapRec__anon1533787c0211::MipMapRec233     MipMapRec(const SkBitmapCacheDesc& desc, const SkMipmap* result)
234         : fKey(desc)
235         , fMipMap(result)
236     {
237         fMipMap->attachToCacheAndRef();
238     }
239 
~MipMapRec__anon1533787c0211::MipMapRec240     ~MipMapRec() override {
241         fMipMap->detachFromCacheAndUnref();
242     }
243 
getKey__anon1533787c0211::MipMapRec244     const Key& getKey() const override { return fKey; }
bytesUsed__anon1533787c0211::MipMapRec245     size_t bytesUsed() const override { return sizeof(fKey) + fMipMap->size(); }
getCategory__anon1533787c0211::MipMapRec246     const char* getCategory() const override { return "mipmap"; }
diagnostic_only_getDiscardable__anon1533787c0211::MipMapRec247     SkDiscardableMemory* diagnostic_only_getDiscardable() const override {
248         return fMipMap->diagnostic_only_getDiscardable();
249     }
250 
Finder__anon1533787c0211::MipMapRec251     static bool Finder(const SkResourceCache::Rec& baseRec, void* contextMip) {
252         const MipMapRec& rec = static_cast<const MipMapRec&>(baseRec);
253         const SkMipmap* mm = SkRef(rec.fMipMap);
254         // the call to ref() above triggers a "lock" in the case of discardable memory,
255         // which means we can now check for null (in case the lock failed).
256         if (nullptr == mm->data()) {
257             mm->unref();    // balance our call to ref()
258             return false;
259         }
260         // the call must call unref() when they are done.
261         *(const SkMipmap**)contextMip = mm;
262         return true;
263     }
264 
265 private:
266     MipMapKey       fKey;
267     const SkMipmap* fMipMap;
268 };
269 }  // namespace
270 
FindAndRef(const SkBitmapCacheDesc & desc,SkResourceCache * localCache)271 const SkMipmap* SkMipmapCache::FindAndRef(const SkBitmapCacheDesc& desc,
272                                           SkResourceCache* localCache) {
273     MipMapKey key(desc);
274     const SkMipmap* result;
275 
276     if (!CHECK_LOCAL(localCache, find, Find, key, MipMapRec::Finder, &result)) {
277         result = nullptr;
278     }
279     return result;
280 }
281 
get_fact(SkResourceCache * localCache)282 static SkResourceCache::DiscardableFactory get_fact(SkResourceCache* localCache) {
283     return localCache ? localCache->discardableFactory()
284                       : SkResourceCache::GetDiscardableFactory();
285 }
286 
AddAndRef(const SkImage_Base * image,SkResourceCache * localCache)287 const SkMipmap* SkMipmapCache::AddAndRef(const SkImage_Base* image, SkResourceCache* localCache) {
288     SkBitmap src;
289     if (!image->getROPixels(nullptr, &src)) {
290         return nullptr;
291     }
292 
293     SkMipmap* mipmap = SkMipmap::Build(src, get_fact(localCache));
294     if (mipmap) {
295         MipMapRec* rec = new MipMapRec(SkBitmapCacheDesc::Make(image), mipmap);
296         CHECK_LOCAL(localCache, add, Add, rec);
297         image->notifyAddedToRasterCache();
298     }
299     return mipmap;
300 }
301