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 "SkResourceCache.h"
10 #include "SkMipMap.h"
11 #include "SkPixelRef.h"
12 #include "SkRect.h"
13 
14 /**
15  *  Use this for bitmapcache and mipmapcache entries.
16  */
SkMakeResourceCacheSharedIDForBitmap(uint32_t bitmapGenID)17 uint64_t SkMakeResourceCacheSharedIDForBitmap(uint32_t bitmapGenID) {
18     uint64_t sharedID = SkSetFourByteTag('b', 'm', 'a', 'p');
19     return (sharedID << 32) | bitmapGenID;
20 }
21 
SkNotifyBitmapGenIDIsStale(uint32_t bitmapGenID)22 void SkNotifyBitmapGenIDIsStale(uint32_t bitmapGenID) {
23     SkResourceCache::PostPurgeSharedID(SkMakeResourceCacheSharedIDForBitmap(bitmapGenID));
24 }
25 
26 ///////////////////////////////////////////////////////////////////////////////////////////////////
27 
GetAllocator()28 SkBitmap::Allocator* SkBitmapCache::GetAllocator() {
29     return SkResourceCache::GetAllocator();
30 }
31 
32 /**
33  This function finds the bounds of the bitmap *within its pixelRef*.
34  If the bitmap lacks a pixelRef, it will return an empty rect, since
35  that doesn't make sense.  This may be a useful enough function that
36  it should be somewhere else (in SkBitmap?).
37  */
get_bounds_from_bitmap(const SkBitmap & bm)38 static SkIRect get_bounds_from_bitmap(const SkBitmap& bm) {
39     if (!(bm.pixelRef())) {
40         return SkIRect::MakeEmpty();
41     }
42     SkIPoint origin = bm.pixelRefOrigin();
43     return SkIRect::MakeXYWH(origin.fX, origin.fY, bm.width(), bm.height());
44 }
45 
46 namespace {
47 static unsigned gBitmapKeyNamespaceLabel;
48 
49 struct BitmapKey : public SkResourceCache::Key {
50 public:
BitmapKey__anon2a2c9cf70111::BitmapKey51     BitmapKey(uint32_t genID, SkScalar sx, SkScalar sy, const SkIRect& bounds)
52         : fGenID(genID)
53         , fScaleX(sx)
54         , fScaleY(sy)
55         , fBounds(bounds)
56     {
57         this->init(&gBitmapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(genID),
58                    sizeof(fGenID) + sizeof(fScaleX) + sizeof(fScaleY) + sizeof(fBounds));
59     }
60 
61     uint32_t    fGenID;
62     SkScalar    fScaleX;
63     SkScalar    fScaleY;
64     SkIRect     fBounds;
65 };
66 
67 struct BitmapRec : public SkResourceCache::Rec {
BitmapRec__anon2a2c9cf70111::BitmapRec68     BitmapRec(uint32_t genID, SkScalar scaleX, SkScalar scaleY, const SkIRect& bounds,
69               const SkBitmap& result)
70         : fKey(genID, scaleX, scaleY, bounds)
71         , fBitmap(result)
72     {}
73 
getKey__anon2a2c9cf70111::BitmapRec74     const Key& getKey() const override { return fKey; }
bytesUsed__anon2a2c9cf70111::BitmapRec75     size_t bytesUsed() const override { return sizeof(fKey) + fBitmap.getSize(); }
76 
Finder__anon2a2c9cf70111::BitmapRec77     static bool Finder(const SkResourceCache::Rec& baseRec, void* contextBitmap) {
78         const BitmapRec& rec = static_cast<const BitmapRec&>(baseRec);
79         SkBitmap* result = (SkBitmap*)contextBitmap;
80 
81         *result = rec.fBitmap;
82         result->lockPixels();
83         return SkToBool(result->getPixels());
84     }
85 
86 private:
87     BitmapKey   fKey;
88     SkBitmap    fBitmap;
89 };
90 } // namespace
91 
92 #define CHECK_LOCAL(localCache, localName, globalName, ...) \
93     ((localCache) ? localCache->localName(__VA_ARGS__) : SkResourceCache::globalName(__VA_ARGS__))
94 
Find(const SkBitmap & src,SkScalar invScaleX,SkScalar invScaleY,SkBitmap * result,SkResourceCache * localCache)95 bool SkBitmapCache::Find(const SkBitmap& src, SkScalar invScaleX, SkScalar invScaleY, SkBitmap* result,
96                          SkResourceCache* localCache) {
97     if (0 == invScaleX || 0 == invScaleY) {
98         // degenerate, and the key we use for mipmaps
99         return false;
100     }
101     BitmapKey key(src.getGenerationID(), invScaleX, invScaleY, get_bounds_from_bitmap(src));
102 
103     return CHECK_LOCAL(localCache, find, Find, key, BitmapRec::Finder, result);
104 }
105 
Add(const SkBitmap & src,SkScalar invScaleX,SkScalar invScaleY,const SkBitmap & result,SkResourceCache * localCache)106 void SkBitmapCache::Add(const SkBitmap& src, SkScalar invScaleX, SkScalar invScaleY,
107                         const SkBitmap& result, SkResourceCache* localCache) {
108     if (0 == invScaleX || 0 == invScaleY) {
109         // degenerate, and the key we use for mipmaps
110         return;
111     }
112     SkASSERT(result.isImmutable());
113     BitmapRec* rec = SkNEW_ARGS(BitmapRec, (src.getGenerationID(), invScaleX, invScaleY,
114                                             get_bounds_from_bitmap(src), result));
115     CHECK_LOCAL(localCache, add, Add, rec);
116     src.pixelRef()->notifyAddedToCache();
117 }
118 
Find(uint32_t genID,const SkIRect & subset,SkBitmap * result,SkResourceCache * localCache)119 bool SkBitmapCache::Find(uint32_t genID, const SkIRect& subset, SkBitmap* result,
120                          SkResourceCache* localCache) {
121     BitmapKey key(genID, SK_Scalar1, SK_Scalar1, subset);
122 
123     return CHECK_LOCAL(localCache, find, Find, key, BitmapRec::Finder, result);
124 }
125 
Add(SkPixelRef * pr,const SkIRect & subset,const SkBitmap & result,SkResourceCache * localCache)126 bool SkBitmapCache::Add(SkPixelRef* pr, const SkIRect& subset, const SkBitmap& result,
127                         SkResourceCache* localCache) {
128     SkASSERT(result.isImmutable());
129 
130     if (subset.isEmpty()
131         || subset.top() < 0
132         || subset.left() < 0
133         || result.width() != subset.width()
134         || result.height() != subset.height()) {
135         return false;
136     } else {
137         BitmapRec* rec = SkNEW_ARGS(BitmapRec, (pr->getGenerationID(), 1, 1, subset, result));
138 
139         CHECK_LOCAL(localCache, add, Add, rec);
140         pr->notifyAddedToCache();
141         return true;
142     }
143 }
144 
145 //////////////////////////////////////////////////////////////////////////////////////////
146 //////////////////////////////////////////////////////////////////////////////////////////
147 
148 namespace {
149 static unsigned gMipMapKeyNamespaceLabel;
150 
151 struct MipMapKey : public SkResourceCache::Key {
152 public:
MipMapKey__anon2a2c9cf70211::MipMapKey153     MipMapKey(uint32_t genID, const SkIRect& bounds) : fGenID(genID), fBounds(bounds) {
154         this->init(&gMipMapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(genID),
155                    sizeof(fGenID) + sizeof(fBounds));
156     }
157 
158     uint32_t    fGenID;
159     SkIRect     fBounds;
160 };
161 
162 struct MipMapRec : public SkResourceCache::Rec {
MipMapRec__anon2a2c9cf70211::MipMapRec163     MipMapRec(const SkBitmap& src, const SkMipMap* result)
164         : fKey(src.getGenerationID(), get_bounds_from_bitmap(src))
165         , fMipMap(result)
166     {
167         fMipMap->attachToCacheAndRef();
168     }
169 
~MipMapRec__anon2a2c9cf70211::MipMapRec170     virtual ~MipMapRec() {
171         fMipMap->detachFromCacheAndUnref();
172     }
173 
getKey__anon2a2c9cf70211::MipMapRec174     const Key& getKey() const override { return fKey; }
bytesUsed__anon2a2c9cf70211::MipMapRec175     size_t bytesUsed() const override { return sizeof(fKey) + fMipMap->size(); }
176 
Finder__anon2a2c9cf70211::MipMapRec177     static bool Finder(const SkResourceCache::Rec& baseRec, void* contextMip) {
178         const MipMapRec& rec = static_cast<const MipMapRec&>(baseRec);
179         const SkMipMap* mm = SkRef(rec.fMipMap);
180         // the call to ref() above triggers a "lock" in the case of discardable memory,
181         // which means we can now check for null (in case the lock failed).
182         if (NULL == mm->data()) {
183             mm->unref();    // balance our call to ref()
184             return false;
185         }
186         // the call must call unref() when they are done.
187         *(const SkMipMap**)contextMip = mm;
188         return true;
189     }
190 
191 private:
192     MipMapKey       fKey;
193     const SkMipMap* fMipMap;
194 };
195 }
196 
FindAndRef(const SkBitmap & src,SkResourceCache * localCache)197 const SkMipMap* SkMipMapCache::FindAndRef(const SkBitmap& src, SkResourceCache* localCache) {
198     MipMapKey key(src.getGenerationID(), get_bounds_from_bitmap(src));
199     const SkMipMap* result;
200 
201     if (!CHECK_LOCAL(localCache, find, Find, key, MipMapRec::Finder, &result)) {
202         result = NULL;
203     }
204     return result;
205 }
206 
get_fact(SkResourceCache * localCache)207 static SkResourceCache::DiscardableFactory get_fact(SkResourceCache* localCache) {
208     return localCache ? localCache->GetDiscardableFactory()
209                       : SkResourceCache::GetDiscardableFactory();
210 }
211 
AddAndRef(const SkBitmap & src,SkResourceCache * localCache)212 const SkMipMap* SkMipMapCache::AddAndRef(const SkBitmap& src, SkResourceCache* localCache) {
213     SkMipMap* mipmap = SkMipMap::Build(src, get_fact(localCache));
214     if (mipmap) {
215         MipMapRec* rec = SkNEW_ARGS(MipMapRec, (src, mipmap));
216         CHECK_LOCAL(localCache, add, Add, rec);
217         src.pixelRef()->notifyAddedToCache();
218     }
219     return mipmap;
220 }
221