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