blob: c411a1bd9dad18daba37f9e9d2c94cd52ccc7b32 [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"
reed04617132014-08-21 09:46:49 -070011#include "SkRect.h"
12
reed7eeba252015-02-24 13:54:23 -080013/**
14 * Use this for bitmapcache and mipmapcache entries.
15 */
16uint64_t SkMakeResourceCacheSharedIDForBitmap(uint32_t bitmapGenID) {
17 uint64_t sharedID = SkSetFourByteTag('b', 'm', 'a', 'p');
18 return (sharedID << 32) | bitmapGenID;
19}
20
21void SkNotifyBitmapGenIDIsStale(uint32_t bitmapGenID) {
22 SkResourceCache::PostPurgeSharedID(SkMakeResourceCacheSharedIDForBitmap(bitmapGenID));
23}
24
25///////////////////////////////////////////////////////////////////////////////////////////////////
26
reed14b6aba2014-08-29 10:25:26 -070027SkBitmap::Allocator* SkBitmapCache::GetAllocator() {
28 return SkResourceCache::GetAllocator();
29}
30
reed04617132014-08-21 09:46:49 -070031/**
32 This function finds the bounds of the bitmap *within its pixelRef*.
33 If the bitmap lacks a pixelRef, it will return an empty rect, since
34 that doesn't make sense. This may be a useful enough function that
35 it should be somewhere else (in SkBitmap?).
36 */
37static SkIRect get_bounds_from_bitmap(const SkBitmap& bm) {
38 if (!(bm.pixelRef())) {
39 return SkIRect::MakeEmpty();
40 }
41 SkIPoint origin = bm.pixelRefOrigin();
42 return SkIRect::MakeXYWH(origin.fX, origin.fY, bm.width(), bm.height());
43}
44
fmalita171e5b72014-10-22 11:20:40 -070045namespace {
46static unsigned gBitmapKeyNamespaceLabel;
47
reed011f39a2014-08-28 13:35:23 -070048struct BitmapKey : public SkResourceCache::Key {
reed04617132014-08-21 09:46:49 -070049public:
reed7eeba252015-02-24 13:54:23 -080050 BitmapKey(uint32_t genID, SkScalar sx, SkScalar sy, const SkIRect& bounds)
51 : fGenID(genID)
52 , fScaleX(sx)
53 , fScaleY(sy)
54 , fBounds(bounds)
reed04617132014-08-21 09:46:49 -070055 {
reed7eeba252015-02-24 13:54:23 -080056 this->init(&gBitmapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(genID),
fmalita171e5b72014-10-22 11:20:40 -070057 sizeof(fGenID) + sizeof(fScaleX) + sizeof(fScaleY) + sizeof(fBounds));
reed04617132014-08-21 09:46:49 -070058 }
qiankun.miao045bb7f2014-08-25 06:08:25 -070059
reed04617132014-08-21 09:46:49 -070060 uint32_t fGenID;
61 SkScalar fScaleX;
62 SkScalar fScaleY;
63 SkIRect fBounds;
64};
65
reed011f39a2014-08-28 13:35:23 -070066struct BitmapRec : public SkResourceCache::Rec {
reed680fb9e2014-08-26 09:08:04 -070067 BitmapRec(uint32_t genID, SkScalar scaleX, SkScalar scaleY, const SkIRect& bounds,
68 const SkBitmap& result)
69 : fKey(genID, scaleX, scaleY, bounds)
70 , fBitmap(result)
71 {}
72
mtklein72c9faa2015-01-09 10:06:39 -080073 const Key& getKey() const SK_OVERRIDE { return fKey; }
74 size_t bytesUsed() const SK_OVERRIDE { return sizeof(fKey) + fBitmap.getSize(); }
reed680fb9e2014-08-26 09:08:04 -070075
reed7eeba252015-02-24 13:54:23 -080076 static bool Finder(const SkResourceCache::Rec& baseRec, void* contextBitmap) {
reedc90e0142014-09-15 11:39:44 -070077 const BitmapRec& rec = static_cast<const BitmapRec&>(baseRec);
78 SkBitmap* result = (SkBitmap*)contextBitmap;
reed595aa052014-09-15 10:15:18 -070079
reedc90e0142014-09-15 11:39:44 -070080 *result = rec.fBitmap;
reed595aa052014-09-15 10:15:18 -070081 result->lockPixels();
reedc90e0142014-09-15 11:39:44 -070082 return SkToBool(result->getPixels());
reed595aa052014-09-15 10:15:18 -070083 }
reed7eeba252015-02-24 13:54:23 -080084
85private:
86 BitmapKey fKey;
87 SkBitmap fBitmap;
reedc90e0142014-09-15 11:39:44 -070088};
fmalita171e5b72014-10-22 11:20:40 -070089} // namespace
reed595aa052014-09-15 10:15:18 -070090
reed30ad5302014-09-16 10:39:55 -070091#define CHECK_LOCAL(localCache, localName, globalName, ...) \
reed9d93c2e2014-10-08 05:17:12 -070092 ((localCache) ? localCache->localName(__VA_ARGS__) : SkResourceCache::globalName(__VA_ARGS__))
reed30ad5302014-09-16 10:39:55 -070093
94bool SkBitmapCache::Find(const SkBitmap& src, SkScalar invScaleX, SkScalar invScaleY, SkBitmap* result,
95 SkResourceCache* localCache) {
reed04617132014-08-21 09:46:49 -070096 if (0 == invScaleX || 0 == invScaleY) {
97 // degenerate, and the key we use for mipmaps
reed680fb9e2014-08-26 09:08:04 -070098 return false;
reed04617132014-08-21 09:46:49 -070099 }
100 BitmapKey key(src.getGenerationID(), invScaleX, invScaleY, get_bounds_from_bitmap(src));
reed30ad5302014-09-16 10:39:55 -0700101
reed7eeba252015-02-24 13:54:23 -0800102 return CHECK_LOCAL(localCache, find, Find, key, BitmapRec::Finder, result);
reed04617132014-08-21 09:46:49 -0700103}
104
reed680fb9e2014-08-26 09:08:04 -0700105void SkBitmapCache::Add(const SkBitmap& src, SkScalar invScaleX, SkScalar invScaleY,
reed30ad5302014-09-16 10:39:55 -0700106 const SkBitmap& result, SkResourceCache* localCache) {
reed04617132014-08-21 09:46:49 -0700107 if (0 == invScaleX || 0 == invScaleY) {
108 // degenerate, and the key we use for mipmaps
reed680fb9e2014-08-26 09:08:04 -0700109 return;
reed04617132014-08-21 09:46:49 -0700110 }
reed14b6aba2014-08-29 10:25:26 -0700111 SkASSERT(result.isImmutable());
reed30ad5302014-09-16 10:39:55 -0700112 BitmapRec* rec = SkNEW_ARGS(BitmapRec, (src.getGenerationID(), invScaleX, invScaleY,
113 get_bounds_from_bitmap(src), result));
114 CHECK_LOCAL(localCache, add, Add, rec);
reed04617132014-08-21 09:46:49 -0700115}
116
reed30ad5302014-09-16 10:39:55 -0700117bool SkBitmapCache::Find(uint32_t genID, const SkIRect& subset, SkBitmap* result,
118 SkResourceCache* localCache) {
piotaixr42b0dfe2014-09-03 11:33:13 -0700119 BitmapKey key(genID, SK_Scalar1, SK_Scalar1, subset);
reed30ad5302014-09-16 10:39:55 -0700120
reed7eeba252015-02-24 13:54:23 -0800121 return CHECK_LOCAL(localCache, find, Find, key, BitmapRec::Finder, result);
reed04617132014-08-21 09:46:49 -0700122}
123
reed30ad5302014-09-16 10:39:55 -0700124bool SkBitmapCache::Add(uint32_t genID, const SkIRect& subset, const SkBitmap& result,
125 SkResourceCache* localCache) {
reed14b6aba2014-08-29 10:25:26 -0700126 SkASSERT(result.isImmutable());
reed04617132014-08-21 09:46:49 -0700127
piotaixr42b0dfe2014-09-03 11:33:13 -0700128 if (subset.isEmpty()
129 || subset.top() < 0
130 || subset.left() < 0
131 || result.width() != subset.width()
132 || result.height() != subset.height()) {
133 return false;
134 } else {
reed30ad5302014-09-16 10:39:55 -0700135 BitmapRec* rec = SkNEW_ARGS(BitmapRec, (genID, SK_Scalar1, SK_Scalar1, subset, result));
piotaixr42b0dfe2014-09-03 11:33:13 -0700136
reed30ad5302014-09-16 10:39:55 -0700137 CHECK_LOCAL(localCache, add, Add, rec);
piotaixr42b0dfe2014-09-03 11:33:13 -0700138 return true;
139 }
140}
reed7eeba252015-02-24 13:54:23 -0800141
reed680fb9e2014-08-26 09:08:04 -0700142//////////////////////////////////////////////////////////////////////////////////////////
reed7eeba252015-02-24 13:54:23 -0800143//////////////////////////////////////////////////////////////////////////////////////////
144
145namespace {
146static unsigned gMipMapKeyNamespaceLabel;
147
148struct MipMapKey : public SkResourceCache::Key {
149public:
150 MipMapKey(uint32_t genID, const SkIRect& bounds) : fGenID(genID), fBounds(bounds) {
151 this->init(&gMipMapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(genID),
152 sizeof(fGenID) + sizeof(fBounds));
153 }
154
155 uint32_t fGenID;
156 SkIRect fBounds;
157};
reed04617132014-08-21 09:46:49 -0700158
reed011f39a2014-08-28 13:35:23 -0700159struct MipMapRec : public SkResourceCache::Rec {
reed680fb9e2014-08-26 09:08:04 -0700160 MipMapRec(const SkBitmap& src, const SkMipMap* result)
reed7eeba252015-02-24 13:54:23 -0800161 : fKey(src.getGenerationID(), get_bounds_from_bitmap(src))
reed9d93c2e2014-10-08 05:17:12 -0700162 , fMipMap(result)
163 {
164 fMipMap->attachToCacheAndRef();
reed92561a02014-10-02 13:47:08 -0700165 }
piotaixr42b0dfe2014-09-03 11:33:13 -0700166
reed9d93c2e2014-10-08 05:17:12 -0700167 virtual ~MipMapRec() {
168 fMipMap->detachFromCacheAndUnref();
169 }
reed37c5a812014-10-03 13:23:30 -0700170
mtklein72c9faa2015-01-09 10:06:39 -0800171 const Key& getKey() const SK_OVERRIDE { return fKey; }
172 size_t bytesUsed() const SK_OVERRIDE { return sizeof(fKey) + fMipMap->size(); }
reed680fb9e2014-08-26 09:08:04 -0700173
reed7eeba252015-02-24 13:54:23 -0800174 static bool Finder(const SkResourceCache::Rec& baseRec, void* contextMip) {
reedc90e0142014-09-15 11:39:44 -0700175 const MipMapRec& rec = static_cast<const MipMapRec&>(baseRec);
reed9d93c2e2014-10-08 05:17:12 -0700176 const SkMipMap* mm = SkRef(rec.fMipMap);
177 // the call to ref() above triggers a "lock" in the case of discardable memory,
178 // which means we can now check for null (in case the lock failed).
179 if (NULL == mm->data()) {
180 mm->unref(); // balance our call to ref()
181 return false;
182 }
183 // the call must call unref() when they are done.
184 *(const SkMipMap**)contextMip = mm;
reedc90e0142014-09-15 11:39:44 -0700185 return true;
186 }
reed9d93c2e2014-10-08 05:17:12 -0700187
188private:
reed7eeba252015-02-24 13:54:23 -0800189 MipMapKey fKey;
reed9d93c2e2014-10-08 05:17:12 -0700190 const SkMipMap* fMipMap;
reedc90e0142014-09-15 11:39:44 -0700191};
reed7eeba252015-02-24 13:54:23 -0800192}
reed595aa052014-09-15 10:15:18 -0700193
reed9d93c2e2014-10-08 05:17:12 -0700194const SkMipMap* SkMipMapCache::FindAndRef(const SkBitmap& src, SkResourceCache* localCache) {
reed7eeba252015-02-24 13:54:23 -0800195 MipMapKey key(src.getGenerationID(), get_bounds_from_bitmap(src));
reedc90e0142014-09-15 11:39:44 -0700196 const SkMipMap* result;
reed9d93c2e2014-10-08 05:17:12 -0700197
reed7eeba252015-02-24 13:54:23 -0800198 if (!CHECK_LOCAL(localCache, find, Find, key, MipMapRec::Finder, &result)) {
reedc90e0142014-09-15 11:39:44 -0700199 result = NULL;
reed680fb9e2014-08-26 09:08:04 -0700200 }
201 return result;
reed04617132014-08-21 09:46:49 -0700202}
203
reed9d93c2e2014-10-08 05:17:12 -0700204static SkResourceCache::DiscardableFactory get_fact(SkResourceCache* localCache) {
205 return localCache ? localCache->GetDiscardableFactory()
206 : SkResourceCache::GetDiscardableFactory();
207}
208
209const SkMipMap* SkMipMapCache::AddAndRef(const SkBitmap& src, SkResourceCache* localCache) {
210 SkMipMap* mipmap = SkMipMap::Build(src, get_fact(localCache));
211 if (mipmap) {
212 MipMapRec* rec = SkNEW_ARGS(MipMapRec, (src, mipmap));
213 CHECK_LOCAL(localCache, add, Add, rec);
reed680fb9e2014-08-26 09:08:04 -0700214 }
reed9d93c2e2014-10-08 05:17:12 -0700215 return mipmap;
reed04617132014-08-21 09:46:49 -0700216}