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