blob: dfa387bb3992e351dd5eba4aa1495c075a98ca3d [file] [log] [blame]
reed04617132014-08-21 09:46:49 -07001/*
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"
reed011f39a2014-08-28 13:35:23 -07009#include "SkResourceCache.h"
reed680fb9e2014-08-26 09:08:04 -070010#include "SkMipMap.h"
reed83787d02015-02-25 07:17:11 -080011#include "SkPixelRef.h"
reed04617132014-08-21 09:46:49 -070012#include "SkRect.h"
13
reed7eeba252015-02-24 13:54:23 -080014/**
15 * Use this for bitmapcache and mipmapcache entries.
16 */
17uint64_t SkMakeResourceCacheSharedIDForBitmap(uint32_t bitmapGenID) {
18 uint64_t sharedID = SkSetFourByteTag('b', 'm', 'a', 'p');
19 return (sharedID << 32) | bitmapGenID;
20}
21
22void SkNotifyBitmapGenIDIsStale(uint32_t bitmapGenID) {
23 SkResourceCache::PostPurgeSharedID(SkMakeResourceCacheSharedIDForBitmap(bitmapGenID));
24}
25
26///////////////////////////////////////////////////////////////////////////////////////////////////
27
reed14b6aba2014-08-29 10:25:26 -070028SkBitmap::Allocator* SkBitmapCache::GetAllocator() {
29 return SkResourceCache::GetAllocator();
30}
31
reed04617132014-08-21 09:46:49 -070032/**
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 */
38static 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
fmalita171e5b72014-10-22 11:20:40 -070046namespace {
47static unsigned gBitmapKeyNamespaceLabel;
48
reed011f39a2014-08-28 13:35:23 -070049struct BitmapKey : public SkResourceCache::Key {
reed04617132014-08-21 09:46:49 -070050public:
reed99138872015-08-31 15:16:17 -070051 BitmapKey(uint32_t genID, int width, int height, const SkIRect& bounds)
reed7eeba252015-02-24 13:54:23 -080052 : fGenID(genID)
reed99138872015-08-31 15:16:17 -070053 , fWidth(width)
54 , fHeight(height)
reed7eeba252015-02-24 13:54:23 -080055 , fBounds(bounds)
reed04617132014-08-21 09:46:49 -070056 {
reed7eeba252015-02-24 13:54:23 -080057 this->init(&gBitmapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(genID),
reed99138872015-08-31 15:16:17 -070058 sizeof(fGenID) + sizeof(fWidth) + sizeof(fHeight) + sizeof(fBounds));
reed04617132014-08-21 09:46:49 -070059 }
qiankun.miao045bb7f2014-08-25 06:08:25 -070060
reed995b4bd2015-09-14 10:27:57 -070061 void dump() const {
62 SkDebugf("-- add [%d %d] %d [%d %d %d %d]\n", fWidth, fHeight, fGenID,
63 fBounds.x(), fBounds.y(), fBounds.width(), fBounds.height());
64 }
65
reed99138872015-08-31 15:16:17 -070066 const uint32_t fGenID;
67 const int fWidth;
68 const int fHeight;
69 const SkIRect fBounds;
reed04617132014-08-21 09:46:49 -070070};
71
reed011f39a2014-08-28 13:35:23 -070072struct BitmapRec : public SkResourceCache::Rec {
reed99138872015-08-31 15:16:17 -070073 BitmapRec(uint32_t genID, int width, int height, const SkIRect& bounds,
reed680fb9e2014-08-26 09:08:04 -070074 const SkBitmap& result)
reed99138872015-08-31 15:16:17 -070075 : fKey(genID, width, height, bounds)
reed680fb9e2014-08-26 09:08:04 -070076 , fBitmap(result)
reed995b4bd2015-09-14 10:27:57 -070077 {
78#ifdef TRACE_NEW_BITMAP_CACHE_RECS
79 fKey.dump();
80#endif
81 }
reed680fb9e2014-08-26 09:08:04 -070082
mtklein36352bf2015-03-25 18:17:31 -070083 const Key& getKey() const override { return fKey; }
84 size_t bytesUsed() const override { return sizeof(fKey) + fBitmap.getSize(); }
reed680fb9e2014-08-26 09:08:04 -070085
reed216b6432015-08-19 12:25:40 -070086 const char* getCategory() const override { return "bitmap"; }
87 SkDiscardableMemory* diagnostic_only_getDiscardable() const override {
88 return fBitmap.pixelRef()->diagnostic_only_getDiscardable();
89 }
90
reed7eeba252015-02-24 13:54:23 -080091 static bool Finder(const SkResourceCache::Rec& baseRec, void* contextBitmap) {
reedc90e0142014-09-15 11:39:44 -070092 const BitmapRec& rec = static_cast<const BitmapRec&>(baseRec);
93 SkBitmap* result = (SkBitmap*)contextBitmap;
reed595aa052014-09-15 10:15:18 -070094
reedc90e0142014-09-15 11:39:44 -070095 *result = rec.fBitmap;
reed595aa052014-09-15 10:15:18 -070096 result->lockPixels();
reedc90e0142014-09-15 11:39:44 -070097 return SkToBool(result->getPixels());
reed595aa052014-09-15 10:15:18 -070098 }
reed7eeba252015-02-24 13:54:23 -080099
100private:
101 BitmapKey fKey;
102 SkBitmap fBitmap;
reedc90e0142014-09-15 11:39:44 -0700103};
fmalita171e5b72014-10-22 11:20:40 -0700104} // namespace
reed595aa052014-09-15 10:15:18 -0700105
reed30ad5302014-09-16 10:39:55 -0700106#define CHECK_LOCAL(localCache, localName, globalName, ...) \
reed9d93c2e2014-10-08 05:17:12 -0700107 ((localCache) ? localCache->localName(__VA_ARGS__) : SkResourceCache::globalName(__VA_ARGS__))
reed30ad5302014-09-16 10:39:55 -0700108
reed99138872015-08-31 15:16:17 -0700109bool SkBitmapCache::FindWH(const SkBitmap& src, int width, int height, SkBitmap* result,
110 SkResourceCache* localCache) {
111 if (0 == width || 0 == height) {
reed04617132014-08-21 09:46:49 -0700112 // degenerate, and the key we use for mipmaps
reed680fb9e2014-08-26 09:08:04 -0700113 return false;
reed04617132014-08-21 09:46:49 -0700114 }
reed99138872015-08-31 15:16:17 -0700115 BitmapKey key(src.getGenerationID(), width, height, get_bounds_from_bitmap(src));
reed30ad5302014-09-16 10:39:55 -0700116
reed7eeba252015-02-24 13:54:23 -0800117 return CHECK_LOCAL(localCache, find, Find, key, BitmapRec::Finder, result);
reed04617132014-08-21 09:46:49 -0700118}
119
reed99138872015-08-31 15:16:17 -0700120void SkBitmapCache::AddWH(const SkBitmap& src, int width, int height,
121 const SkBitmap& result, SkResourceCache* localCache) {
122 if (0 == width || 0 == height) {
reed04617132014-08-21 09:46:49 -0700123 // degenerate, and the key we use for mipmaps
reed680fb9e2014-08-26 09:08:04 -0700124 return;
reed04617132014-08-21 09:46:49 -0700125 }
reed14b6aba2014-08-29 10:25:26 -0700126 SkASSERT(result.isImmutable());
reed99138872015-08-31 15:16:17 -0700127 BitmapRec* rec = new BitmapRec(src.getGenerationID(), width, height,
halcanary385fe4d2015-08-26 13:07:48 -0700128 get_bounds_from_bitmap(src), result);
reed30ad5302014-09-16 10:39:55 -0700129 CHECK_LOCAL(localCache, add, Add, rec);
reed83787d02015-02-25 07:17:11 -0800130 src.pixelRef()->notifyAddedToCache();
reed04617132014-08-21 09:46:49 -0700131}
132
reed30ad5302014-09-16 10:39:55 -0700133bool SkBitmapCache::Find(uint32_t genID, const SkIRect& subset, SkBitmap* result,
134 SkResourceCache* localCache) {
piotaixr42b0dfe2014-09-03 11:33:13 -0700135 BitmapKey key(genID, SK_Scalar1, SK_Scalar1, subset);
reed30ad5302014-09-16 10:39:55 -0700136
reed7eeba252015-02-24 13:54:23 -0800137 return CHECK_LOCAL(localCache, find, Find, key, BitmapRec::Finder, result);
reed04617132014-08-21 09:46:49 -0700138}
139
reed83787d02015-02-25 07:17:11 -0800140bool SkBitmapCache::Add(SkPixelRef* pr, const SkIRect& subset, const SkBitmap& result,
reed30ad5302014-09-16 10:39:55 -0700141 SkResourceCache* localCache) {
reed14b6aba2014-08-29 10:25:26 -0700142 SkASSERT(result.isImmutable());
reed04617132014-08-21 09:46:49 -0700143
piotaixr42b0dfe2014-09-03 11:33:13 -0700144 if (subset.isEmpty()
145 || subset.top() < 0
146 || subset.left() < 0
147 || result.width() != subset.width()
148 || result.height() != subset.height()) {
149 return false;
150 } else {
halcanary385fe4d2015-08-26 13:07:48 -0700151 BitmapRec* rec = new BitmapRec(pr->getGenerationID(), 1, 1, subset, result);
piotaixr42b0dfe2014-09-03 11:33:13 -0700152
reed30ad5302014-09-16 10:39:55 -0700153 CHECK_LOCAL(localCache, add, Add, rec);
reed83787d02015-02-25 07:17:11 -0800154 pr->notifyAddedToCache();
piotaixr42b0dfe2014-09-03 11:33:13 -0700155 return true;
156 }
157}
reed7eeba252015-02-24 13:54:23 -0800158
reed6f1216a2015-08-04 08:10:13 -0700159bool SkBitmapCache::Find(uint32_t genID, SkBitmap* result, SkResourceCache* localCache) {
160 BitmapKey key(genID, SK_Scalar1, SK_Scalar1, SkIRect::MakeEmpty());
161
162 return CHECK_LOCAL(localCache, find, Find, key, BitmapRec::Finder, result);
163}
164
165void SkBitmapCache::Add(uint32_t genID, const SkBitmap& result, SkResourceCache* localCache) {
166 SkASSERT(result.isImmutable());
167
halcanary385fe4d2015-08-26 13:07:48 -0700168 BitmapRec* rec = new BitmapRec(genID, 1, 1, SkIRect::MakeEmpty(), result);
reed6f1216a2015-08-04 08:10:13 -0700169
170 CHECK_LOCAL(localCache, add, Add, rec);
171}
172
reed680fb9e2014-08-26 09:08:04 -0700173//////////////////////////////////////////////////////////////////////////////////////////
reed7eeba252015-02-24 13:54:23 -0800174//////////////////////////////////////////////////////////////////////////////////////////
175
176namespace {
177static unsigned gMipMapKeyNamespaceLabel;
178
179struct MipMapKey : public SkResourceCache::Key {
180public:
181 MipMapKey(uint32_t genID, const SkIRect& bounds) : fGenID(genID), fBounds(bounds) {
182 this->init(&gMipMapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(genID),
183 sizeof(fGenID) + sizeof(fBounds));
184 }
185
186 uint32_t fGenID;
187 SkIRect fBounds;
188};
reed04617132014-08-21 09:46:49 -0700189
reed011f39a2014-08-28 13:35:23 -0700190struct MipMapRec : public SkResourceCache::Rec {
reed680fb9e2014-08-26 09:08:04 -0700191 MipMapRec(const SkBitmap& src, const SkMipMap* result)
reed7eeba252015-02-24 13:54:23 -0800192 : fKey(src.getGenerationID(), get_bounds_from_bitmap(src))
reed9d93c2e2014-10-08 05:17:12 -0700193 , fMipMap(result)
194 {
195 fMipMap->attachToCacheAndRef();
reed92561a02014-10-02 13:47:08 -0700196 }
piotaixr42b0dfe2014-09-03 11:33:13 -0700197
reed9d93c2e2014-10-08 05:17:12 -0700198 virtual ~MipMapRec() {
199 fMipMap->detachFromCacheAndUnref();
200 }
reed37c5a812014-10-03 13:23:30 -0700201
mtklein36352bf2015-03-25 18:17:31 -0700202 const Key& getKey() const override { return fKey; }
203 size_t bytesUsed() const override { return sizeof(fKey) + fMipMap->size(); }
reed216b6432015-08-19 12:25:40 -0700204 const char* getCategory() const override { return "mipmap"; }
205 SkDiscardableMemory* diagnostic_only_getDiscardable() const override {
206 return fMipMap->diagnostic_only_getDiscardable();
207 }
reed680fb9e2014-08-26 09:08:04 -0700208
reed7eeba252015-02-24 13:54:23 -0800209 static bool Finder(const SkResourceCache::Rec& baseRec, void* contextMip) {
reedc90e0142014-09-15 11:39:44 -0700210 const MipMapRec& rec = static_cast<const MipMapRec&>(baseRec);
reed9d93c2e2014-10-08 05:17:12 -0700211 const SkMipMap* mm = SkRef(rec.fMipMap);
212 // the call to ref() above triggers a "lock" in the case of discardable memory,
213 // which means we can now check for null (in case the lock failed).
halcanary96fcdcc2015-08-27 07:41:13 -0700214 if (nullptr == mm->data()) {
reed9d93c2e2014-10-08 05:17:12 -0700215 mm->unref(); // balance our call to ref()
216 return false;
217 }
218 // the call must call unref() when they are done.
219 *(const SkMipMap**)contextMip = mm;
reedc90e0142014-09-15 11:39:44 -0700220 return true;
221 }
reed9d93c2e2014-10-08 05:17:12 -0700222
223private:
reed7eeba252015-02-24 13:54:23 -0800224 MipMapKey fKey;
reed9d93c2e2014-10-08 05:17:12 -0700225 const SkMipMap* fMipMap;
reedc90e0142014-09-15 11:39:44 -0700226};
reed7eeba252015-02-24 13:54:23 -0800227}
reed595aa052014-09-15 10:15:18 -0700228
reed9d93c2e2014-10-08 05:17:12 -0700229const SkMipMap* SkMipMapCache::FindAndRef(const SkBitmap& src, SkResourceCache* localCache) {
reed7eeba252015-02-24 13:54:23 -0800230 MipMapKey key(src.getGenerationID(), get_bounds_from_bitmap(src));
reedc90e0142014-09-15 11:39:44 -0700231 const SkMipMap* result;
reed9d93c2e2014-10-08 05:17:12 -0700232
reed7eeba252015-02-24 13:54:23 -0800233 if (!CHECK_LOCAL(localCache, find, Find, key, MipMapRec::Finder, &result)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700234 result = nullptr;
reed680fb9e2014-08-26 09:08:04 -0700235 }
236 return result;
reed04617132014-08-21 09:46:49 -0700237}
238
reed9d93c2e2014-10-08 05:17:12 -0700239static SkResourceCache::DiscardableFactory get_fact(SkResourceCache* localCache) {
240 return localCache ? localCache->GetDiscardableFactory()
241 : SkResourceCache::GetDiscardableFactory();
242}
243
244const SkMipMap* SkMipMapCache::AddAndRef(const SkBitmap& src, SkResourceCache* localCache) {
245 SkMipMap* mipmap = SkMipMap::Build(src, get_fact(localCache));
246 if (mipmap) {
halcanary385fe4d2015-08-26 13:07:48 -0700247 MipMapRec* rec = new MipMapRec(src, mipmap);
reed9d93c2e2014-10-08 05:17:12 -0700248 CHECK_LOCAL(localCache, add, Add, rec);
reed83787d02015-02-25 07:17:11 -0800249 src.pixelRef()->notifyAddedToCache();
reed680fb9e2014-08-26 09:08:04 -0700250 }
reed9d93c2e2014-10-08 05:17:12 -0700251 return mipmap;
reed04617132014-08-21 09:46:49 -0700252}