Flutter Engine
The Flutter Engine
SkBitmapCache.cpp
Go to the documentation of this file.
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
9
15#include "include/core/SkRect.h"
21#include "src/core/SkMipmap.h"
22#include "src/core/SkNextID.h"
25
26#include <cstddef>
27#include <utility>
28
29/**
30 * Use this for bitmapcache and mipmapcache entries.
31 */
32uint64_t SkMakeResourceCacheSharedIDForBitmap(uint32_t bitmapGenID) {
33 uint64_t sharedID = SkSetFourByteTag('b', 'm', 'a', 'p');
34 return (sharedID << 32) | bitmapGenID;
35}
36
37void SkNotifyBitmapGenIDIsStale(uint32_t bitmapGenID) {
39}
40
41///////////////////////////////////////////////////////////////////////////////////////////////////
42
43SkBitmapCacheDesc SkBitmapCacheDesc::Make(uint32_t imageID, const SkIRect& subset) {
44 SkASSERT(imageID);
45 SkASSERT(subset.width() > 0 && subset.height() > 0);
46 return { imageID, subset };
47}
48
51 return Make(image->uniqueID(), bounds);
52}
53
54namespace {
55static unsigned gBitmapKeyNamespaceLabel;
56
57struct BitmapKey : public SkResourceCache::Key {
58public:
59 BitmapKey(const SkBitmapCacheDesc& desc) : fDesc(desc) {
60 this->init(&gBitmapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(fDesc.fImageID),
61 sizeof(fDesc));
62 }
63
64 const SkBitmapCacheDesc fDesc;
65};
66} // namespace
67
68//////////////////////
69
71 pr->setImmutableWithID(id);
72}
73
75public:
76 Rec(const SkBitmapCacheDesc& desc, const SkImageInfo& info, size_t rowBytes,
77 std::unique_ptr<SkDiscardableMemory> dm, void* block)
78 : fKey(desc)
79 , fDM(std::move(dm))
80 , fMalloc(block)
81 , fInfo(info)
82 , fRowBytes(rowBytes)
83 {
84 SkASSERT(!(fDM && fMalloc)); // can't have both
85
86 // We need an ID to return with the bitmap/pixelref. We can't necessarily use the key/desc
87 // ID - lazy images cache the same ID with multiple keys (in different color types).
88 fPrUniqueID = SkNextID::ImageID();
89 }
90
91 ~Rec() override {
92 SkASSERT(0 == fExternalCounter);
93 if (fDM && fDiscardableIsLocked) {
94 SkASSERT(fDM->data());
95 fDM->unlock();
96 }
97 sk_free(fMalloc); // may be null
98 }
99
100 const Key& getKey() const override { return fKey; }
101 size_t bytesUsed() const override {
102 return sizeof(fKey) + fInfo.computeByteSize(fRowBytes);
103 }
104 bool canBePurged() override {
105 SkAutoMutexExclusive ama(fMutex);
106 return fExternalCounter == 0;
107 }
108 void postAddInstall(void* payload) override {
109 SkAssertResult(this->install(static_cast<SkBitmap*>(payload)));
110 }
111
112 const char* getCategory() const override { return "bitmap"; }
114 return fDM.get();
115 }
116
117 static void ReleaseProc(void* addr, void* ctx) {
118 Rec* rec = static_cast<Rec*>(ctx);
119 SkAutoMutexExclusive ama(rec->fMutex);
120
121 SkASSERT(rec->fExternalCounter > 0);
122 rec->fExternalCounter -= 1;
123 if (rec->fDM) {
124 SkASSERT(rec->fMalloc == nullptr);
125 if (rec->fExternalCounter == 0) {
126 rec->fDM->unlock();
127 rec->fDiscardableIsLocked = false;
128 }
129 } else {
130 SkASSERT(rec->fMalloc != nullptr);
131 }
132 }
133
135 SkAutoMutexExclusive ama(fMutex);
136
137 if (!fDM && !fMalloc) {
138 return false;
139 }
140
141 if (fDM) {
142 if (!fDiscardableIsLocked) {
143 SkASSERT(fExternalCounter == 0);
144 if (!fDM->lock()) {
145 fDM.reset(nullptr);
146 return false;
147 }
148 fDiscardableIsLocked = true;
149 }
150 SkASSERT(fDM->data());
151 }
152
153 bitmap->installPixels(fInfo, fDM ? fDM->data() : fMalloc, fRowBytes, ReleaseProc, this);
154 SkBitmapCache_setImmutableWithID(bitmap->pixelRef(), fPrUniqueID);
155 fExternalCounter++;
156
157 return true;
158 }
159
160 static bool Finder(const SkResourceCache::Rec& baseRec, void* contextBitmap) {
161 Rec* rec = const_cast<Rec*>(static_cast<const Rec*>(&baseRec));
162 SkBitmap* result = (SkBitmap*)contextBitmap;
163 return rec->install(result);
164 }
165
166private:
167 BitmapKey fKey;
168
169 SkMutex fMutex;
170
171 // either fDM or fMalloc can be non-null, but not both
172 std::unique_ptr<SkDiscardableMemory> fDM;
173 void* fMalloc;
174
175 SkImageInfo fInfo;
176 size_t fRowBytes;
177 uint32_t fPrUniqueID;
178
179 // This field counts the number of external pixelrefs we have created.
180 // They notify us when they are destroyed so we can decrement this.
181 int fExternalCounter = 0;
182 bool fDiscardableIsLocked = true;
183};
184
185void SkBitmapCache::PrivateDeleteRec(Rec* rec) { delete rec; }
186
188 SkPixmap* pmap) {
189 // Ensure that the info matches the subset (i.e. the subset is the entire image)
190 SkASSERT(info.width() == desc.fSubset.width());
191 SkASSERT(info.height() == desc.fSubset.height());
192
193 const size_t rb = info.minRowBytes();
194 size_t size = info.computeByteSize(rb);
196 return nullptr;
197 }
198
199 std::unique_ptr<SkDiscardableMemory> dm;
200 void* block = nullptr;
201
203 if (factory) {
204 dm.reset(factory(size));
205 } else {
206 block = sk_malloc_canfail(size);
207 }
208 if (!dm && !block) {
209 return nullptr;
210 }
211 *pmap = SkPixmap(info, dm ? dm->data() : block, rb);
212 return RecPtr(new Rec(desc, info, rb, std::move(dm), block));
213}
214
216 SkResourceCache::Add(rec.release(), bitmap);
217}
218
220 desc.validate();
222}
223
224//////////////////////////////////////////////////////////////////////////////////////////
225//////////////////////////////////////////////////////////////////////////////////////////
226
227#define CHECK_LOCAL(localCache, localName, globalName, ...) \
228 ((localCache) ? localCache->localName(__VA_ARGS__) : SkResourceCache::globalName(__VA_ARGS__))
229
230namespace {
231static unsigned gMipMapKeyNamespaceLabel;
232
233struct MipMapKey : public SkResourceCache::Key {
234public:
235 MipMapKey(const SkBitmapCacheDesc& desc) : fDesc(desc) {
236 this->init(&gMipMapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(fDesc.fImageID),
237 sizeof(fDesc));
238 }
239
240 const SkBitmapCacheDesc fDesc;
241};
242
243struct MipMapRec : public SkResourceCache::Rec {
244 MipMapRec(const SkBitmapCacheDesc& desc, const SkMipmap* result)
245 : fKey(desc)
246 , fMipMap(result)
247 {
248 fMipMap->attachToCacheAndRef();
249 }
250
251 ~MipMapRec() override {
252 fMipMap->detachFromCacheAndUnref();
253 }
254
255 const Key& getKey() const override { return fKey; }
256 size_t bytesUsed() const override { return sizeof(fKey) + fMipMap->size(); }
257 const char* getCategory() const override { return "mipmap"; }
259 return fMipMap->diagnostic_only_getDiscardable();
260 }
261
262 static bool Finder(const SkResourceCache::Rec& baseRec, void* contextMip) {
263 const MipMapRec& rec = static_cast<const MipMapRec&>(baseRec);
264 const SkMipmap* mm = SkRef(rec.fMipMap);
265 // the call to ref() above triggers a "lock" in the case of discardable memory,
266 // which means we can now check for null (in case the lock failed).
267 if (nullptr == mm->data()) {
268 mm->unref(); // balance our call to ref()
269 return false;
270 }
271 // the call must call unref() when they are done.
272 *(const SkMipmap**)contextMip = mm;
273 return true;
274 }
275
276private:
277 MipMapKey fKey;
278 const SkMipmap* fMipMap;
279};
280} // namespace
281
283 SkResourceCache* localCache) {
284 MipMapKey key(desc);
285 const SkMipmap* result;
286
287 if (!CHECK_LOCAL(localCache, find, Find, key, MipMapRec::Finder, &result)) {
288 result = nullptr;
289 }
290 return result;
291}
292
294 return localCache ? localCache->discardableFactory()
296}
297
300 if (!image->getROPixels(nullptr, &src)) {
301 return nullptr;
302 }
303
304 SkMipmap* mipmap = SkMipmap::Build(src, get_fact(localCache));
305 if (mipmap) {
306 MipMapRec* rec = new MipMapRec(SkBitmapCacheDesc::Make(image), mipmap);
307 CHECK_LOCAL(localCache, add, Add, rec);
308 image->notifyAddedToRasterCache();
309 }
310 return mipmap;
311}
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
SkAssertResult(font.textToGlyphs("Hello", 5, SkTextEncoding::kUTF8, glyphs, std::size(glyphs))==count)
TArray< uint32_t > Key
#define SkASSERT(cond)
Definition: SkAssert.h:116
uint64_t SkMakeResourceCacheSharedIDForBitmap(uint32_t bitmapGenID)
void SkBitmapCache_setImmutableWithID(SkPixelRef *pr, uint32_t id)
void SkNotifyBitmapGenIDIsStale(uint32_t bitmapGenID)
#define CHECK_LOCAL(localCache, localName, globalName,...)
static SkResourceCache::DiscardableFactory get_fact(SkResourceCache *localCache)
SK_API void sk_free(void *)
static void * sk_malloc_canfail(size_t size)
Definition: SkMalloc.h:93
static T * SkRef(T *obj)
Definition: SkRefCnt.h:132
static constexpr SkFourByteTag SkSetFourByteTag(char a, char b, char c, char d)
Definition: SkTypes.h:167
int find(T *array, int N, T item)
bool canBePurged() override
void postAddInstall(void *payload) override
SkDiscardableMemory * diagnostic_only_getDiscardable() const override
const Key & getKey() const override
static void ReleaseProc(void *addr, void *ctx)
size_t bytesUsed() const override
static bool Finder(const SkResourceCache::Rec &baseRec, void *contextBitmap)
const char * getCategory() const override
bool install(SkBitmap *bitmap)
Rec(const SkBitmapCacheDesc &desc, const SkImageInfo &info, size_t rowBytes, std::unique_ptr< SkDiscardableMemory > dm, void *block)
std::unique_ptr< Rec, RecDeleter > RecPtr
Definition: SkBitmapCache.h:53
static RecPtr Alloc(const SkBitmapCacheDesc &, const SkImageInfo &, SkPixmap *)
static bool Find(const SkBitmapCacheDesc &, SkBitmap *result)
static void Add(RecPtr, SkBitmap *)
void unref() const
Definition: SkCachedData.h:31
const void * data() const
Definition: SkCachedData.h:26
uint32_t uniqueID() const
Definition: SkImage.h:311
int width() const
Definition: SkImage.h:285
int height() const
Definition: SkImage.h:291
static const SkMipmap * AddAndRef(const SkImage_Base *, SkResourceCache *localCache=nullptr)
static const SkMipmap * FindAndRef(const SkBitmapCacheDesc &, SkResourceCache *localCache=nullptr)
static SkMipmap * Build(const SkPixmap &src, SkDiscardableFactoryProc, bool computeContents=true)
Definition: SkMipmap.cpp:45
static uint32_t ImageID()
Definition: SkPixelRef.cpp:19
static void Add(Rec *, void *payload=nullptr)
DiscardableFactory discardableFactory() const
static void PostPurgeSharedID(uint64_t sharedID)
static DiscardableFactory GetDiscardableFactory()
static bool Find(const Key &key, FindVisitor, void *context)
SkDiscardableMemory *(* DiscardableFactory)(size_t bytes)
GAsyncResult * result
Optional< SkRect > bounds
Definition: SkRecords.h:189
sk_sp< const SkImage > image
Definition: SkRecords.h:269
Definition: bitmap.py:1
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
Definition: ref_ptr.h:256
static SkBitmapCacheDesc Make(const SkImage *)
Definition: SkRect.h:32
constexpr int32_t height() const
Definition: SkRect.h:165
constexpr int32_t width() const
Definition: SkRect.h:158
static constexpr SkIRect MakeWH(int32_t w, int32_t h)
Definition: SkRect.h:56
static bool ByteSizeOverflowed(size_t byteSize)
Definition: SkImageInfo.h:588
size_t computeByteSize(size_t rowBytes) const
void init(void *nameSpace, uint64_t sharedID, size_t dataSize)
virtual const char * getCategory() const =0
virtual SkDiscardableMemory * diagnostic_only_getDiscardable() const
virtual size_t bytesUsed() const =0
virtual const Key & getKey() const =0