Line data Source code
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 : */
18 0 : uint64_t SkMakeResourceCacheSharedIDForBitmap(uint32_t bitmapGenID) {
19 0 : uint64_t sharedID = SkSetFourByteTag('b', 'm', 'a', 'p');
20 0 : return (sharedID << 32) | bitmapGenID;
21 : }
22 :
23 0 : void SkNotifyBitmapGenIDIsStale(uint32_t bitmapGenID) {
24 0 : SkResourceCache::PostPurgeSharedID(SkMakeResourceCacheSharedIDForBitmap(bitmapGenID));
25 0 : }
26 :
27 : ///////////////////////////////////////////////////////////////////////////////////////////////////
28 :
29 : /**
30 : This function finds the bounds of the bitmap *within its pixelRef*.
31 : If the bitmap lacks a pixelRef, it will return an empty rect, since
32 : that doesn't make sense. This may be a useful enough function that
33 : it should be somewhere else (in SkBitmap?).
34 : */
35 0 : static SkIRect get_bounds_from_bitmap(const SkBitmap& bm) {
36 0 : if (!(bm.pixelRef())) {
37 0 : return SkIRect::MakeEmpty();
38 : }
39 0 : SkIPoint origin = bm.pixelRefOrigin();
40 0 : return SkIRect::MakeXYWH(origin.fX, origin.fY, bm.width(), bm.height());
41 : }
42 :
43 : /**
44 : * This function finds the bounds of the image. Today this is just the entire bounds,
45 : * but in the future we may support subsets within an image, in which case this should
46 : * return that subset (see get_bounds_from_bitmap).
47 : */
48 0 : static SkIRect get_bounds_from_image(const SkImage* image) {
49 0 : SkASSERT(image->width() > 0 && image->height() > 0);
50 0 : return SkIRect::MakeWH(image->width(), image->height());
51 : }
52 :
53 0 : SkBitmapCacheDesc SkBitmapCacheDesc::Make(uint32_t imageID, int origWidth, int origHeight) {
54 0 : SkASSERT(imageID);
55 0 : SkASSERT(origWidth > 0 && origHeight > 0);
56 0 : return { imageID, 0, 0, {0, 0, origWidth, origHeight} };
57 : }
58 :
59 0 : SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkBitmap& bm, int scaledWidth, int scaledHeight) {
60 0 : SkASSERT(bm.width() > 0 && bm.height() > 0);
61 0 : SkASSERT(scaledWidth > 0 && scaledHeight > 0);
62 0 : SkASSERT(scaledWidth != bm.width() || scaledHeight != bm.height());
63 :
64 0 : return { bm.getGenerationID(), scaledWidth, scaledHeight, get_bounds_from_bitmap(bm) };
65 : }
66 :
67 0 : SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkBitmap& bm) {
68 0 : SkASSERT(bm.width() > 0 && bm.height() > 0);
69 0 : SkASSERT(bm.pixelRefOrigin() == SkIPoint::Make(0, 0));
70 :
71 0 : return { bm.getGenerationID(), 0, 0, get_bounds_from_bitmap(bm) };
72 : }
73 :
74 0 : SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkImage* image, int scaledWidth, int scaledHeight) {
75 0 : SkASSERT(image->width() > 0 && image->height() > 0);
76 0 : SkASSERT(scaledWidth > 0 && scaledHeight > 0);
77 :
78 : // If the dimensions are the same, should we set them to 0,0?
79 : //SkASSERT(scaledWidth != image->width() || scaledHeight != image->height());
80 :
81 0 : return { image->uniqueID(), scaledWidth, scaledHeight, get_bounds_from_image(image) };
82 : }
83 :
84 0 : SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkImage* image) {
85 0 : SkASSERT(image->width() > 0 && image->height() > 0);
86 :
87 0 : return { image->uniqueID(), 0, 0, get_bounds_from_image(image) };
88 : }
89 :
90 : namespace {
91 : static unsigned gBitmapKeyNamespaceLabel;
92 :
93 : struct BitmapKey : public SkResourceCache::Key {
94 : public:
95 0 : BitmapKey(const SkBitmapCacheDesc& desc) : fDesc(desc) {
96 0 : this->init(&gBitmapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(fDesc.fImageID),
97 0 : sizeof(fDesc));
98 0 : }
99 :
100 : void dump() const {
101 : SkDebugf("-- add [%d %d] %d [%d %d %d %d]\n",
102 : fDesc.fScaledWidth, fDesc.fScaledHeight, fDesc.fImageID,
103 : fDesc.fSubset.x(), fDesc.fSubset.y(), fDesc.fSubset.width(), fDesc.fSubset.height());
104 : }
105 :
106 : const SkBitmapCacheDesc fDesc;
107 : };
108 : }
109 :
110 : //////////////////////
111 : #include "SkDiscardableMemory.h"
112 : #include "SkNextID.h"
113 :
114 0 : void SkBitmapCache_setImmutableWithID(SkPixelRef* pr, uint32_t id) {
115 0 : pr->setImmutableWithID(id);
116 0 : }
117 :
118 : //#define REC_TRACE SkDebugf
119 0 : static void REC_TRACE(const char format[], ...) {}
120 :
121 : // for diagnostics
122 : static int32_t gRecCounter;
123 :
124 : class SkBitmapCache::Rec : public SkResourceCache::Rec {
125 : public:
126 0 : Rec(const SkBitmapCacheDesc& desc, const SkImageInfo& info, size_t rowBytes,
127 : std::unique_ptr<SkDiscardableMemory> dm, void* block)
128 0 : : fKey(desc)
129 0 : , fDM(std::move(dm))
130 : , fMalloc(block)
131 : , fInfo(info)
132 : , fRowBytes(rowBytes)
133 0 : , fExternalCounter(kBeforeFirstInstall_ExternalCounter)
134 : {
135 0 : SkASSERT(!(fDM && fMalloc)); // can't have both
136 :
137 : // We need an ID to return with the bitmap/pixelref.
138 : // If they are not scaling, we can return the same ID as the key/desc
139 : // If they are scaling, we need a new ID
140 0 : if (desc.fScaledWidth == 0 && desc.fScaledHeight == 0) {
141 0 : fPrUniqueID = desc.fImageID;
142 : } else {
143 0 : fPrUniqueID = SkNextID::ImageID();
144 : }
145 0 : REC_TRACE(" Rec(%d): [%d %d] %d\n",
146 0 : sk_atomic_inc(&gRecCounter), fInfo.width(), fInfo.height(), fPrUniqueID);
147 0 : }
148 :
149 0 : ~Rec() override {
150 0 : SkASSERT(0 == fExternalCounter || kBeforeFirstInstall_ExternalCounter == fExternalCounter);
151 0 : if (fDM && kBeforeFirstInstall_ExternalCounter == fExternalCounter) {
152 : // we never installed, so we need to unlock before we destroy the DM
153 0 : SkASSERT(fDM->data());
154 0 : fDM->unlock();
155 : }
156 0 : REC_TRACE("~Rec(%d): [%d %d] %d\n",
157 0 : sk_atomic_dec(&gRecCounter) - 1, fInfo.width(), fInfo.height(), fPrUniqueID);
158 0 : sk_free(fMalloc); // may be null
159 0 : }
160 :
161 0 : const Key& getKey() const override { return fKey; }
162 0 : size_t bytesUsed() const override {
163 0 : return sizeof(fKey) + fInfo.getSafeSize(fRowBytes);
164 : }
165 0 : bool canBePurged() override {
166 0 : SkAutoMutexAcquire ama(fMutex);
167 0 : return fExternalCounter == 0;
168 : }
169 0 : void postAddInstall(void* payload) override {
170 0 : SkAssertResult(this->install(static_cast<SkBitmap*>(payload)));
171 0 : }
172 :
173 0 : const char* getCategory() const override { return "bitmap"; }
174 0 : SkDiscardableMemory* diagnostic_only_getDiscardable() const override {
175 0 : return fDM.get();
176 : }
177 :
178 0 : static void ReleaseProc(void* addr, void* ctx) {
179 0 : Rec* rec = static_cast<Rec*>(ctx);
180 0 : SkAutoMutexAcquire ama(rec->fMutex);
181 :
182 0 : REC_TRACE(" Rec: [%d] releaseproc\n", rec->fPrUniqueID);
183 :
184 0 : SkASSERT(rec->fExternalCounter > 0);
185 0 : rec->fExternalCounter -= 1;
186 0 : if (rec->fDM) {
187 0 : SkASSERT(rec->fMalloc == nullptr);
188 0 : if (rec->fExternalCounter == 0) {
189 0 : REC_TRACE(" Rec [%d] unlock\n", rec->fPrUniqueID);
190 0 : rec->fDM->unlock();
191 : }
192 : } else {
193 0 : SkASSERT(rec->fMalloc != nullptr);
194 : }
195 0 : }
196 :
197 0 : bool install(SkBitmap* bitmap) {
198 0 : SkAutoMutexAcquire ama(fMutex);
199 :
200 : // are we still valid
201 0 : if (!fDM && !fMalloc) {
202 0 : REC_TRACE(" Rec: [%d] invalid\n", fPrUniqueID);
203 0 : return false;
204 : }
205 :
206 : /*
207 : constructor fExternalCount < 0 fDM->data()
208 : after install fExternalCount > 0 fDM->data()
209 : after Release fExternalCount == 0 !fDM->data()
210 : */
211 0 : if (fDM) {
212 0 : if (kBeforeFirstInstall_ExternalCounter == fExternalCounter) {
213 0 : SkASSERT(fDM->data());
214 0 : } else if (fExternalCounter > 0) {
215 0 : SkASSERT(fDM->data());
216 : } else {
217 0 : SkASSERT(fExternalCounter == 0);
218 0 : if (!fDM->lock()) {
219 0 : REC_TRACE(" Rec [%d] re-lock failed\n", fPrUniqueID);
220 0 : fDM.reset(nullptr);
221 0 : return false;
222 : }
223 0 : REC_TRACE(" Rec [%d] re-lock succeeded\n", fPrUniqueID);
224 : }
225 0 : SkASSERT(fDM->data());
226 : }
227 :
228 0 : bitmap->installPixels(fInfo, fDM ? fDM->data() : fMalloc, fRowBytes, nullptr,
229 0 : ReleaseProc, this);
230 0 : SkBitmapCache_setImmutableWithID(bitmap->pixelRef(), fPrUniqueID);
231 :
232 0 : REC_TRACE(" Rec: [%d] install new pr\n", fPrUniqueID);
233 :
234 0 : if (kBeforeFirstInstall_ExternalCounter == fExternalCounter) {
235 0 : fExternalCounter = 1;
236 : } else {
237 0 : fExternalCounter += 1;
238 : }
239 0 : SkASSERT(fExternalCounter > 0);
240 0 : return true;
241 : }
242 :
243 0 : static bool Finder(const SkResourceCache::Rec& baseRec, void* contextBitmap) {
244 0 : Rec* rec = (Rec*)&baseRec;
245 0 : SkBitmap* result = (SkBitmap*)contextBitmap;
246 0 : REC_TRACE(" Rec: [%d] found\n", rec->fPrUniqueID);
247 0 : return rec->install(result);
248 : }
249 :
250 : private:
251 : BitmapKey fKey;
252 :
253 : SkMutex fMutex;
254 :
255 : // either fDM or fMalloc can be non-null, but not both
256 : std::unique_ptr<SkDiscardableMemory> fDM;
257 : void* fMalloc;
258 :
259 : SkImageInfo fInfo;
260 : size_t fRowBytes;
261 : uint32_t fPrUniqueID;
262 :
263 : // This field counts the number of external pixelrefs we have created. They notify us when
264 : // they are destroyed so we can decrement this.
265 : //
266 : // > 0 we have outstanding pixelrefs
267 : // == 0 we have no outstanding pixelrefs, and can be safely purged
268 : // < 0 we have been created, but not yet "installed" the first time.
269 : //
270 : int fExternalCounter;
271 :
272 : enum {
273 : kBeforeFirstInstall_ExternalCounter = -1
274 : };
275 : };
276 :
277 0 : void SkBitmapCache::PrivateDeleteRec(Rec* rec) { delete rec; }
278 :
279 0 : SkBitmapCache::RecPtr SkBitmapCache::Alloc(const SkBitmapCacheDesc& desc, const SkImageInfo& info,
280 : SkPixmap* pmap) {
281 : // Ensure that the caller is self-consistent:
282 : // - if they are scaling, the info matches the scaled size
283 : // - if they are not, the info matches the subset (i.e. the subset is the entire image)
284 0 : if (desc.fScaledWidth == 0 && desc.fScaledHeight == 0) {
285 0 : SkASSERT(info.width() == desc.fSubset.width());
286 0 : SkASSERT(info.height() == desc.fSubset.height());
287 : } else {
288 0 : SkASSERT(info.width() == desc.fScaledWidth);
289 0 : SkASSERT(info.height() == desc.fScaledHeight);
290 : }
291 :
292 0 : const size_t rb = info.minRowBytes();
293 0 : size_t size = info.getSafeSize(rb);
294 0 : if (0 == size) {
295 0 : return nullptr;
296 : }
297 :
298 0 : std::unique_ptr<SkDiscardableMemory> dm;
299 0 : void* block = nullptr;
300 :
301 0 : auto factory = SkResourceCache::GetDiscardableFactory();
302 0 : if (factory) {
303 0 : dm.reset(factory(size));
304 : } else {
305 0 : block = sk_malloc_flags(size, 0);
306 : }
307 0 : if (!dm && !block) {
308 0 : return nullptr;
309 : }
310 0 : *pmap = SkPixmap(info, dm ? dm->data() : block, rb);
311 0 : return RecPtr(new Rec(desc, info, rb, std::move(dm), block));
312 : }
313 :
314 0 : void SkBitmapCache::Add(RecPtr rec, SkBitmap* bitmap) {
315 0 : SkResourceCache::Add(rec.release(), bitmap);
316 0 : }
317 :
318 0 : bool SkBitmapCache::Find(const SkBitmapCacheDesc& desc, SkBitmap* result) {
319 0 : desc.validate();
320 0 : return SkResourceCache::Find(BitmapKey(desc), SkBitmapCache::Rec::Finder, result);
321 : }
322 :
323 : //////////////////////////////////////////////////////////////////////////////////////////
324 : //////////////////////////////////////////////////////////////////////////////////////////
325 :
326 : #define CHECK_LOCAL(localCache, localName, globalName, ...) \
327 : ((localCache) ? localCache->localName(__VA_ARGS__) : SkResourceCache::globalName(__VA_ARGS__))
328 :
329 : namespace {
330 : static unsigned gMipMapKeyNamespaceLabel;
331 :
332 : struct MipMapKey : public SkResourceCache::Key {
333 : public:
334 0 : MipMapKey(uint32_t imageID, const SkIRect& subset, SkDestinationSurfaceColorMode colorMode)
335 0 : : fImageID(imageID)
336 0 : , fColorMode(static_cast<uint32_t>(colorMode))
337 0 : , fSubset(subset)
338 : {
339 0 : SkASSERT(fImageID);
340 0 : SkASSERT(!subset.isEmpty());
341 0 : this->init(&gMipMapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(fImageID),
342 0 : sizeof(fImageID) + sizeof(fColorMode) + sizeof(fSubset));
343 0 : }
344 :
345 : uint32_t fImageID;
346 : uint32_t fColorMode;
347 : SkIRect fSubset;
348 : };
349 :
350 : struct MipMapRec : public SkResourceCache::Rec {
351 0 : MipMapRec(uint32_t imageID, const SkIRect& subset, SkDestinationSurfaceColorMode colorMode,
352 : const SkMipMap* result)
353 0 : : fKey(imageID, subset, colorMode)
354 0 : , fMipMap(result)
355 : {
356 0 : fMipMap->attachToCacheAndRef();
357 0 : }
358 :
359 0 : ~MipMapRec() override {
360 0 : fMipMap->detachFromCacheAndUnref();
361 0 : }
362 :
363 0 : const Key& getKey() const override { return fKey; }
364 0 : size_t bytesUsed() const override { return sizeof(fKey) + fMipMap->size(); }
365 0 : const char* getCategory() const override { return "mipmap"; }
366 0 : SkDiscardableMemory* diagnostic_only_getDiscardable() const override {
367 0 : return fMipMap->diagnostic_only_getDiscardable();
368 : }
369 :
370 0 : static bool Finder(const SkResourceCache::Rec& baseRec, void* contextMip) {
371 0 : const MipMapRec& rec = static_cast<const MipMapRec&>(baseRec);
372 0 : const SkMipMap* mm = SkRef(rec.fMipMap);
373 : // the call to ref() above triggers a "lock" in the case of discardable memory,
374 : // which means we can now check for null (in case the lock failed).
375 0 : if (nullptr == mm->data()) {
376 0 : mm->unref(); // balance our call to ref()
377 0 : return false;
378 : }
379 : // the call must call unref() when they are done.
380 0 : *(const SkMipMap**)contextMip = mm;
381 0 : return true;
382 : }
383 :
384 : private:
385 : MipMapKey fKey;
386 : const SkMipMap* fMipMap;
387 : };
388 : }
389 :
390 0 : const SkMipMap* SkMipMapCache::FindAndRef(const SkBitmapCacheDesc& desc,
391 : SkDestinationSurfaceColorMode colorMode,
392 : SkResourceCache* localCache) {
393 0 : SkASSERT(desc.fScaledWidth == 0);
394 0 : SkASSERT(desc.fScaledHeight == 0);
395 0 : MipMapKey key(desc.fImageID, desc.fSubset, colorMode);
396 : const SkMipMap* result;
397 :
398 0 : if (!CHECK_LOCAL(localCache, find, Find, key, MipMapRec::Finder, &result)) {
399 0 : result = nullptr;
400 : }
401 0 : return result;
402 : }
403 :
404 0 : static SkResourceCache::DiscardableFactory get_fact(SkResourceCache* localCache) {
405 0 : return localCache ? localCache->GetDiscardableFactory()
406 0 : : SkResourceCache::GetDiscardableFactory();
407 : }
408 :
409 0 : const SkMipMap* SkMipMapCache::AddAndRef(const SkBitmap& src,
410 : SkDestinationSurfaceColorMode colorMode,
411 : SkResourceCache* localCache) {
412 0 : SkMipMap* mipmap = SkMipMap::Build(src, colorMode, get_fact(localCache));
413 0 : if (mipmap) {
414 0 : MipMapRec* rec = new MipMapRec(src.getGenerationID(), get_bounds_from_bitmap(src),
415 0 : colorMode, mipmap);
416 0 : CHECK_LOCAL(localCache, add, Add, rec);
417 0 : src.pixelRef()->notifyAddedToCache();
418 : }
419 0 : return mipmap;
420 : }
|