• Home
  • History
  • Annotate
  • 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 
GetAllocator()29 SkBitmap::Allocator* SkBitmapCache::GetAllocator() {
30     return SkResourceCache::GetAllocator();
31 }
32 
33 /**
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  */
get_bounds_from_bitmap(const SkBitmap & bm)39 static 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 
47 /**
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  */
get_bounds_from_image(const SkImage * image)52 static SkIRect get_bounds_from_image(const SkImage* image) {
53     SkASSERT(image->width() > 0 && image->height() > 0);
54     return SkIRect::MakeWH(image->width(), image->height());
55 }
56 
Make(uint32_t imageID,int origWidth,int origHeight)57 SkBitmapCacheDesc SkBitmapCacheDesc::Make(uint32_t imageID, int origWidth, int origHeight) {
58     SkASSERT(imageID);
59     SkASSERT(origWidth > 0 && origHeight > 0);
60     return { imageID, 0, 0, {0, 0, origWidth, origHeight} };
61 }
62 
Make(const SkBitmap & bm,int scaledWidth,int scaledHeight)63 SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkBitmap& bm, int scaledWidth, int scaledHeight) {
64     SkASSERT(bm.width() > 0 && bm.height() > 0);
65     SkASSERT(scaledWidth > 0 && scaledHeight > 0);
66     SkASSERT(scaledWidth != bm.width() || scaledHeight != bm.height());
67 
68     return { bm.getGenerationID(), scaledWidth, scaledHeight, get_bounds_from_bitmap(bm) };
69 }
70 
Make(const SkBitmap & bm)71 SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkBitmap& bm) {
72     SkASSERT(bm.width() > 0 && bm.height() > 0);
73     SkASSERT(bm.pixelRefOrigin() == SkIPoint::Make(0, 0));
74 
75     return { bm.getGenerationID(), 0, 0, get_bounds_from_bitmap(bm) };
76 }
77 
Make(const SkImage * image,int scaledWidth,int scaledHeight)78 SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkImage* image, int scaledWidth, int scaledHeight) {
79     SkASSERT(image->width() > 0 && image->height() > 0);
80     SkASSERT(scaledWidth > 0 && scaledHeight > 0);
81 
82     // If the dimensions are the same, should we set them to 0,0?
83     //SkASSERT(scaledWidth != image->width() || scaledHeight != image->height());
84 
85     return { image->uniqueID(), scaledWidth, scaledHeight, get_bounds_from_image(image) };
86 }
87 
Make(const SkImage * image)88 SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkImage* image) {
89     SkASSERT(image->width() > 0 && image->height() > 0);
90 
91     return { image->uniqueID(), 0, 0, get_bounds_from_image(image) };
92 }
93 
94 namespace {
95 static unsigned gBitmapKeyNamespaceLabel;
96 
97 struct BitmapKey : public SkResourceCache::Key {
98 public:
BitmapKey__anon2a2c9cf70111::BitmapKey99     BitmapKey(const SkBitmapCacheDesc& desc) : fDesc(desc) {
100         this->init(&gBitmapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(fDesc.fImageID),
101                    sizeof(fDesc));
102     }
103 
dump__anon2a2c9cf70111::BitmapKey104     void dump() const {
105         SkDebugf("-- add [%d %d] %d [%d %d %d %d]\n",
106                  fDesc.fScaledWidth, fDesc.fScaledHeight, fDesc.fImageID,
107              fDesc.fSubset.x(), fDesc.fSubset.y(), fDesc.fSubset.width(), fDesc.fSubset.height());
108     }
109 
110     const SkBitmapCacheDesc fDesc;
111 };
112 
113 struct BitmapRec : public SkResourceCache::Rec {
BitmapRec__anon2a2c9cf70111::BitmapRec114     BitmapRec(const SkBitmapCacheDesc& desc, const SkBitmap& result)
115         : fKey(desc)
116         , fBitmap(result)
117     {
118 #ifdef TRACE_NEW_BITMAP_CACHE_RECS
119         fKey.dump();
120 #endif
121     }
122 
getKey__anon2a2c9cf70111::BitmapRec123     const Key& getKey() const override { return fKey; }
bytesUsed__anon2a2c9cf70111::BitmapRec124     size_t bytesUsed() const override { return sizeof(fKey) + fBitmap.getSize(); }
125 
getCategory__anon2a2c9cf70111::BitmapRec126     const char* getCategory() const override { return "bitmap"; }
diagnostic_only_getDiscardable__anon2a2c9cf70111::BitmapRec127     SkDiscardableMemory* diagnostic_only_getDiscardable() const override {
128         return fBitmap.pixelRef()->diagnostic_only_getDiscardable();
129     }
130 
Finder__anon2a2c9cf70111::BitmapRec131     static bool Finder(const SkResourceCache::Rec& baseRec, void* contextBitmap) {
132         const BitmapRec& rec = static_cast<const BitmapRec&>(baseRec);
133         SkBitmap* result = (SkBitmap*)contextBitmap;
134 
135         *result = rec.fBitmap;
136         result->lockPixels();
137         return SkToBool(result->getPixels());
138     }
139 
140 private:
141     BitmapKey   fKey;
142     SkBitmap    fBitmap;
143 };
144 } // namespace
145 
146 #define CHECK_LOCAL(localCache, localName, globalName, ...) \
147     ((localCache) ? localCache->localName(__VA_ARGS__) : SkResourceCache::globalName(__VA_ARGS__))
148 
Find(const SkBitmapCacheDesc & desc,SkBitmap * result,SkResourceCache * localCache)149 bool SkBitmapCache::Find(const SkBitmapCacheDesc& desc, SkBitmap* result,
150                          SkResourceCache* localCache) {
151     desc.validate();
152     return CHECK_LOCAL(localCache, find, Find, BitmapKey(desc), BitmapRec::Finder, result);
153 }
154 
Add(const SkBitmapCacheDesc & desc,const SkBitmap & result,SkResourceCache * localCache)155 bool SkBitmapCache::Add(const SkBitmapCacheDesc& desc, const SkBitmap& result,
156                         SkResourceCache* localCache) {
157     desc.validate();
158     SkASSERT(result.isImmutable());
159     BitmapRec* rec = new BitmapRec(desc, result);
160     CHECK_LOCAL(localCache, add, Add, rec);
161     return true;
162 }
163 
164 //////////////////////////////////////////////////////////////////////////////////////////
165 //////////////////////////////////////////////////////////////////////////////////////////
166 
167 namespace {
168 static unsigned gMipMapKeyNamespaceLabel;
169 
170 struct MipMapKey : public SkResourceCache::Key {
171 public:
MipMapKey__anon2a2c9cf70211::MipMapKey172     MipMapKey(uint32_t imageID, const SkIRect& subset, SkDestinationSurfaceColorMode colorMode)
173         : fImageID(imageID)
174         , fColorMode(static_cast<uint32_t>(colorMode))
175         , fSubset(subset)
176     {
177         SkASSERT(fImageID);
178         SkASSERT(!subset.isEmpty());
179         this->init(&gMipMapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(fImageID),
180                    sizeof(fImageID) + sizeof(fColorMode) + sizeof(fSubset));
181     }
182 
183     uint32_t    fImageID;
184     uint32_t    fColorMode;
185     SkIRect     fSubset;
186 };
187 
188 struct MipMapRec : public SkResourceCache::Rec {
MipMapRec__anon2a2c9cf70211::MipMapRec189     MipMapRec(uint32_t imageID, const SkIRect& subset, SkDestinationSurfaceColorMode colorMode,
190               const SkMipMap* result)
191         : fKey(imageID, subset, colorMode)
192         , fMipMap(result)
193     {
194         fMipMap->attachToCacheAndRef();
195     }
196 
~MipMapRec__anon2a2c9cf70211::MipMapRec197     ~MipMapRec() override {
198         fMipMap->detachFromCacheAndUnref();
199     }
200 
getKey__anon2a2c9cf70211::MipMapRec201     const Key& getKey() const override { return fKey; }
bytesUsed__anon2a2c9cf70211::MipMapRec202     size_t bytesUsed() const override { return sizeof(fKey) + fMipMap->size(); }
getCategory__anon2a2c9cf70211::MipMapRec203     const char* getCategory() const override { return "mipmap"; }
diagnostic_only_getDiscardable__anon2a2c9cf70211::MipMapRec204     SkDiscardableMemory* diagnostic_only_getDiscardable() const override {
205         return fMipMap->diagnostic_only_getDiscardable();
206     }
207 
Finder__anon2a2c9cf70211::MipMapRec208     static bool Finder(const SkResourceCache::Rec& baseRec, void* contextMip) {
209         const MipMapRec& rec = static_cast<const MipMapRec&>(baseRec);
210         const SkMipMap* mm = SkRef(rec.fMipMap);
211         // the call to ref() above triggers a "lock" in the case of discardable memory,
212         // which means we can now check for null (in case the lock failed).
213         if (nullptr == mm->data()) {
214             mm->unref();    // balance our call to ref()
215             return false;
216         }
217         // the call must call unref() when they are done.
218         *(const SkMipMap**)contextMip = mm;
219         return true;
220     }
221 
222 private:
223     MipMapKey       fKey;
224     const SkMipMap* fMipMap;
225 };
226 }
227 
FindAndRef(const SkBitmapCacheDesc & desc,SkDestinationSurfaceColorMode colorMode,SkResourceCache * localCache)228 const SkMipMap* SkMipMapCache::FindAndRef(const SkBitmapCacheDesc& desc,
229                                           SkDestinationSurfaceColorMode colorMode,
230                                           SkResourceCache* localCache) {
231     SkASSERT(desc.fScaledWidth == 0);
232     SkASSERT(desc.fScaledHeight == 0);
233     MipMapKey key(desc.fImageID, desc.fSubset, colorMode);
234     const SkMipMap* result;
235 
236     if (!CHECK_LOCAL(localCache, find, Find, key, MipMapRec::Finder, &result)) {
237         result = nullptr;
238     }
239     return result;
240 }
241 
get_fact(SkResourceCache * localCache)242 static SkResourceCache::DiscardableFactory get_fact(SkResourceCache* localCache) {
243     return localCache ? localCache->GetDiscardableFactory()
244                       : SkResourceCache::GetDiscardableFactory();
245 }
246 
AddAndRef(const SkBitmap & src,SkDestinationSurfaceColorMode colorMode,SkResourceCache * localCache)247 const SkMipMap* SkMipMapCache::AddAndRef(const SkBitmap& src,
248                                          SkDestinationSurfaceColorMode colorMode,
249                                          SkResourceCache* localCache) {
250     SkMipMap* mipmap = SkMipMap::Build(src, colorMode, get_fact(localCache));
251     if (mipmap) {
252         MipMapRec* rec = new MipMapRec(src.getGenerationID(), get_bounds_from_bitmap(src),
253                                        colorMode, mipmap);
254         CHECK_LOCAL(localCache, add, Add, rec);
255         src.pixelRef()->notifyAddedToCache();
256     }
257     return mipmap;
258 }
259