blob: 064fc46938e8f0a219992e29c0ca4343065d1f9f [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"
reed98ed7b62015-09-15 12:38:12 -07009#include "SkImage.h"
reed011f39a2014-08-28 13:35:23 -070010#include "SkResourceCache.h"
reed680fb9e2014-08-26 09:08:04 -070011#include "SkMipMap.h"
reed83787d02015-02-25 07:17:11 -080012#include "SkPixelRef.h"
reed04617132014-08-21 09:46:49 -070013#include "SkRect.h"
14
reed7eeba252015-02-24 13:54:23 -080015/**
16 * Use this for bitmapcache and mipmapcache entries.
17 */
18uint64_t SkMakeResourceCacheSharedIDForBitmap(uint32_t bitmapGenID) {
19 uint64_t sharedID = SkSetFourByteTag('b', 'm', 'a', 'p');
20 return (sharedID << 32) | bitmapGenID;
21}
22
23void SkNotifyBitmapGenIDIsStale(uint32_t bitmapGenID) {
24 SkResourceCache::PostPurgeSharedID(SkMakeResourceCacheSharedIDForBitmap(bitmapGenID));
25}
26
27///////////////////////////////////////////////////////////////////////////////////////////////////
28
reed14b6aba2014-08-29 10:25:26 -070029SkBitmap::Allocator* SkBitmapCache::GetAllocator() {
30 return SkResourceCache::GetAllocator();
31}
32
reed04617132014-08-21 09:46:49 -070033/**
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 */
39static 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
reed98ed7b62015-09-15 12:38:12 -070047/**
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 */
52static SkIRect get_bounds_from_image(const SkImage* image) {
Mike Reed5fa3d6d2017-03-25 09:51:00 -040053 SkASSERT(image->width() > 0 && image->height() > 0);
reed98ed7b62015-09-15 12:38:12 -070054 return SkIRect::MakeWH(image->width(), image->height());
55}
56
Mike Reed5fa3d6d2017-03-25 09:51:00 -040057SkBitmapCacheDesc 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
63SkBitmapCacheDesc 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) };
reed98ed7b62015-09-15 12:38:12 -070069}
70
71SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkBitmap& bm) {
Mike Reed5fa3d6d2017-03-25 09:51:00 -040072 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) };
reed98ed7b62015-09-15 12:38:12 -070076}
77
Mike Reed5fa3d6d2017-03-25 09:51:00 -040078SkBitmapCacheDesc 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) };
reed98ed7b62015-09-15 12:38:12 -070086}
87
88SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkImage* image) {
Mike Reed5fa3d6d2017-03-25 09:51:00 -040089 SkASSERT(image->width() > 0 && image->height() > 0);
90
91 return { image->uniqueID(), 0, 0, get_bounds_from_image(image) };
reed98ed7b62015-09-15 12:38:12 -070092}
93
fmalita171e5b72014-10-22 11:20:40 -070094namespace {
95static unsigned gBitmapKeyNamespaceLabel;
96
reed011f39a2014-08-28 13:35:23 -070097struct BitmapKey : public SkResourceCache::Key {
reed04617132014-08-21 09:46:49 -070098public:
Mike Reedd3a2af72016-11-07 14:30:00 -050099 BitmapKey(const SkBitmapCacheDesc& desc) : fDesc(desc) {
100 this->init(&gBitmapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(fDesc.fImageID),
101 sizeof(fDesc));
reed04617132014-08-21 09:46:49 -0700102 }
qiankun.miao045bb7f2014-08-25 06:08:25 -0700103
reed995b4bd2015-09-14 10:27:57 -0700104 void dump() const {
Mike Reed5fa3d6d2017-03-25 09:51:00 -0400105 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());
reed995b4bd2015-09-14 10:27:57 -0700108 }
109
Mike Reedd3a2af72016-11-07 14:30:00 -0500110 const SkBitmapCacheDesc fDesc;
reed04617132014-08-21 09:46:49 -0700111};
112
reed011f39a2014-08-28 13:35:23 -0700113struct BitmapRec : public SkResourceCache::Rec {
reed98ed7b62015-09-15 12:38:12 -0700114 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
mtklein36352bf2015-03-25 18:17:31 -0700123 const Key& getKey() const override { return fKey; }
124 size_t bytesUsed() const override { return sizeof(fKey) + fBitmap.getSize(); }
reed680fb9e2014-08-26 09:08:04 -0700125
reed216b6432015-08-19 12:25:40 -0700126 const char* getCategory() const override { return "bitmap"; }
127 SkDiscardableMemory* diagnostic_only_getDiscardable() const override {
128 return fBitmap.pixelRef()->diagnostic_only_getDiscardable();
129 }
130
reed7eeba252015-02-24 13:54:23 -0800131 static bool Finder(const SkResourceCache::Rec& baseRec, void* contextBitmap) {
reedc90e0142014-09-15 11:39:44 -0700132 const BitmapRec& rec = static_cast<const BitmapRec&>(baseRec);
133 SkBitmap* result = (SkBitmap*)contextBitmap;
reed595aa052014-09-15 10:15:18 -0700134
reedc90e0142014-09-15 11:39:44 -0700135 *result = rec.fBitmap;
reed595aa052014-09-15 10:15:18 -0700136 result->lockPixels();
reedc90e0142014-09-15 11:39:44 -0700137 return SkToBool(result->getPixels());
reed595aa052014-09-15 10:15:18 -0700138 }
reed7eeba252015-02-24 13:54:23 -0800139
140private:
141 BitmapKey fKey;
142 SkBitmap fBitmap;
reedc90e0142014-09-15 11:39:44 -0700143};
fmalita171e5b72014-10-22 11:20:40 -0700144} // namespace
reed595aa052014-09-15 10:15:18 -0700145
reed30ad5302014-09-16 10:39:55 -0700146#define CHECK_LOCAL(localCache, localName, globalName, ...) \
reed9d93c2e2014-10-08 05:17:12 -0700147 ((localCache) ? localCache->localName(__VA_ARGS__) : SkResourceCache::globalName(__VA_ARGS__))
reed30ad5302014-09-16 10:39:55 -0700148
Mike Reed5fa3d6d2017-03-25 09:51:00 -0400149bool SkBitmapCache::Find(const SkBitmapCacheDesc& desc, SkBitmap* result,
150 SkResourceCache* localCache) {
151 desc.validate();
reed98ed7b62015-09-15 12:38:12 -0700152 return CHECK_LOCAL(localCache, find, Find, BitmapKey(desc), BitmapRec::Finder, result);
153}
154
Mike Reed5fa3d6d2017-03-25 09:51:00 -0400155bool SkBitmapCache::Add(const SkBitmapCacheDesc& desc, const SkBitmap& result,
156 SkResourceCache* localCache) {
157 desc.validate();
reed14b6aba2014-08-29 10:25:26 -0700158 SkASSERT(result.isImmutable());
reed98ed7b62015-09-15 12:38:12 -0700159 BitmapRec* rec = new BitmapRec(desc, result);
reed30ad5302014-09-16 10:39:55 -0700160 CHECK_LOCAL(localCache, add, Add, rec);
reed98ed7b62015-09-15 12:38:12 -0700161 return true;
reed04617132014-08-21 09:46:49 -0700162}
163
reed680fb9e2014-08-26 09:08:04 -0700164//////////////////////////////////////////////////////////////////////////////////////////
reed7eeba252015-02-24 13:54:23 -0800165//////////////////////////////////////////////////////////////////////////////////////////
166
167namespace {
168static unsigned gMipMapKeyNamespaceLabel;
169
170struct MipMapKey : public SkResourceCache::Key {
171public:
Mike Reed5fa3d6d2017-03-25 09:51:00 -0400172 MipMapKey(uint32_t imageID, const SkIRect& subset, SkDestinationSurfaceColorMode colorMode)
173 : fImageID(imageID)
174 , fColorMode(static_cast<uint32_t>(colorMode))
175 , fSubset(subset)
reed6644d932016-06-10 11:41:47 -0700176 {
Mike Reed5fa3d6d2017-03-25 09:51:00 -0400177 SkASSERT(fImageID);
178 SkASSERT(!subset.isEmpty());
179 this->init(&gMipMapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(fImageID),
180 sizeof(fImageID) + sizeof(fColorMode) + sizeof(fSubset));
reed7eeba252015-02-24 13:54:23 -0800181 }
182
Mike Reed5fa3d6d2017-03-25 09:51:00 -0400183 uint32_t fImageID;
Brian Osman7b8400d2016-11-08 17:08:54 -0500184 uint32_t fColorMode;
Mike Reed5fa3d6d2017-03-25 09:51:00 -0400185 SkIRect fSubset;
reed7eeba252015-02-24 13:54:23 -0800186};
reed04617132014-08-21 09:46:49 -0700187
reed011f39a2014-08-28 13:35:23 -0700188struct MipMapRec : public SkResourceCache::Rec {
Mike Reed5fa3d6d2017-03-25 09:51:00 -0400189 MipMapRec(uint32_t imageID, const SkIRect& subset, SkDestinationSurfaceColorMode colorMode,
190 const SkMipMap* result)
191 : fKey(imageID, subset, colorMode)
reed9d93c2e2014-10-08 05:17:12 -0700192 , fMipMap(result)
193 {
194 fMipMap->attachToCacheAndRef();
reed92561a02014-10-02 13:47:08 -0700195 }
piotaixr42b0dfe2014-09-03 11:33:13 -0700196
Brian Salomond3b65972017-03-22 12:05:03 -0400197 ~MipMapRec() override {
reed9d93c2e2014-10-08 05:17:12 -0700198 fMipMap->detachFromCacheAndUnref();
199 }
reed37c5a812014-10-03 13:23:30 -0700200
mtklein36352bf2015-03-25 18:17:31 -0700201 const Key& getKey() const override { return fKey; }
202 size_t bytesUsed() const override { return sizeof(fKey) + fMipMap->size(); }
reed216b6432015-08-19 12:25:40 -0700203 const char* getCategory() const override { return "mipmap"; }
204 SkDiscardableMemory* diagnostic_only_getDiscardable() const override {
205 return fMipMap->diagnostic_only_getDiscardable();
206 }
reed680fb9e2014-08-26 09:08:04 -0700207
reed7eeba252015-02-24 13:54:23 -0800208 static bool Finder(const SkResourceCache::Rec& baseRec, void* contextMip) {
reedc90e0142014-09-15 11:39:44 -0700209 const MipMapRec& rec = static_cast<const MipMapRec&>(baseRec);
reed9d93c2e2014-10-08 05:17:12 -0700210 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).
halcanary96fcdcc2015-08-27 07:41:13 -0700213 if (nullptr == mm->data()) {
reed9d93c2e2014-10-08 05:17:12 -0700214 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;
reedc90e0142014-09-15 11:39:44 -0700219 return true;
220 }
reed9d93c2e2014-10-08 05:17:12 -0700221
222private:
reed7eeba252015-02-24 13:54:23 -0800223 MipMapKey fKey;
reed9d93c2e2014-10-08 05:17:12 -0700224 const SkMipMap* fMipMap;
reedc90e0142014-09-15 11:39:44 -0700225};
reed7eeba252015-02-24 13:54:23 -0800226}
reed595aa052014-09-15 10:15:18 -0700227
reed98ed7b62015-09-15 12:38:12 -0700228const SkMipMap* SkMipMapCache::FindAndRef(const SkBitmapCacheDesc& desc,
Brian Osman7b8400d2016-11-08 17:08:54 -0500229 SkDestinationSurfaceColorMode colorMode,
reed98ed7b62015-09-15 12:38:12 -0700230 SkResourceCache* localCache) {
Mike Reed5fa3d6d2017-03-25 09:51:00 -0400231 SkASSERT(desc.fScaledWidth == 0);
232 SkASSERT(desc.fScaledHeight == 0);
233 MipMapKey key(desc.fImageID, desc.fSubset, colorMode);
reedc90e0142014-09-15 11:39:44 -0700234 const SkMipMap* result;
reed9d93c2e2014-10-08 05:17:12 -0700235
reed7eeba252015-02-24 13:54:23 -0800236 if (!CHECK_LOCAL(localCache, find, Find, key, MipMapRec::Finder, &result)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700237 result = nullptr;
reed680fb9e2014-08-26 09:08:04 -0700238 }
239 return result;
reed04617132014-08-21 09:46:49 -0700240}
241
reed9d93c2e2014-10-08 05:17:12 -0700242static SkResourceCache::DiscardableFactory get_fact(SkResourceCache* localCache) {
243 return localCache ? localCache->GetDiscardableFactory()
244 : SkResourceCache::GetDiscardableFactory();
245}
246
Brian Osman7b8400d2016-11-08 17:08:54 -0500247const SkMipMap* SkMipMapCache::AddAndRef(const SkBitmap& src,
248 SkDestinationSurfaceColorMode colorMode,
reed6644d932016-06-10 11:41:47 -0700249 SkResourceCache* localCache) {
Brian Osman7b8400d2016-11-08 17:08:54 -0500250 SkMipMap* mipmap = SkMipMap::Build(src, colorMode, get_fact(localCache));
reed9d93c2e2014-10-08 05:17:12 -0700251 if (mipmap) {
Mike Reed5fa3d6d2017-03-25 09:51:00 -0400252 MipMapRec* rec = new MipMapRec(src.getGenerationID(), get_bounds_from_bitmap(src),
253 colorMode, mipmap);
reed9d93c2e2014-10-08 05:17:12 -0700254 CHECK_LOCAL(localCache, add, Add, rec);
reed83787d02015-02-25 07:17:11 -0800255 src.pixelRef()->notifyAddedToCache();
reed680fb9e2014-08-26 09:08:04 -0700256 }
reed9d93c2e2014-10-08 05:17:12 -0700257 return mipmap;
reed04617132014-08-21 09:46:49 -0700258}