1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2014 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "include/core/SkImage.h"
9cb93a386Sopenharmony_ci#include "include/core/SkPixelRef.h"
10cb93a386Sopenharmony_ci#include "include/core/SkRect.h"
11cb93a386Sopenharmony_ci#include "src/core/SkBitmapCache.h"
12cb93a386Sopenharmony_ci#include "src/core/SkMipmap.h"
13cb93a386Sopenharmony_ci#include "src/core/SkResourceCache.h"
14cb93a386Sopenharmony_ci#include "src/image/SkImage_Base.h"
15cb93a386Sopenharmony_ci
16cb93a386Sopenharmony_ci/**
17cb93a386Sopenharmony_ci *  Use this for bitmapcache and mipmapcache entries.
18cb93a386Sopenharmony_ci */
19cb93a386Sopenharmony_ciuint64_t SkMakeResourceCacheSharedIDForBitmap(uint32_t bitmapGenID) {
20cb93a386Sopenharmony_ci    uint64_t sharedID = SkSetFourByteTag('b', 'm', 'a', 'p');
21cb93a386Sopenharmony_ci    return (sharedID << 32) | bitmapGenID;
22cb93a386Sopenharmony_ci}
23cb93a386Sopenharmony_ci
24cb93a386Sopenharmony_civoid SkNotifyBitmapGenIDIsStale(uint32_t bitmapGenID) {
25cb93a386Sopenharmony_ci    SkResourceCache::PostPurgeSharedID(SkMakeResourceCacheSharedIDForBitmap(bitmapGenID));
26cb93a386Sopenharmony_ci}
27cb93a386Sopenharmony_ci
28cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////////////////////////
29cb93a386Sopenharmony_ci
30cb93a386Sopenharmony_ciSkBitmapCacheDesc SkBitmapCacheDesc::Make(uint32_t imageID, const SkIRect& subset) {
31cb93a386Sopenharmony_ci    SkASSERT(imageID);
32cb93a386Sopenharmony_ci    SkASSERT(subset.width() > 0 && subset.height() > 0);
33cb93a386Sopenharmony_ci    return { imageID, subset };
34cb93a386Sopenharmony_ci}
35cb93a386Sopenharmony_ci
36cb93a386Sopenharmony_ciSkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkImage* image) {
37cb93a386Sopenharmony_ci    SkIRect bounds = SkIRect::MakeWH(image->width(), image->height());
38cb93a386Sopenharmony_ci    return Make(image->uniqueID(), bounds);
39cb93a386Sopenharmony_ci}
40cb93a386Sopenharmony_ci
41cb93a386Sopenharmony_cinamespace {
42cb93a386Sopenharmony_cistatic unsigned gBitmapKeyNamespaceLabel;
43cb93a386Sopenharmony_ci
44cb93a386Sopenharmony_cistruct BitmapKey : public SkResourceCache::Key {
45cb93a386Sopenharmony_cipublic:
46cb93a386Sopenharmony_ci    BitmapKey(const SkBitmapCacheDesc& desc) : fDesc(desc) {
47cb93a386Sopenharmony_ci        this->init(&gBitmapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(fDesc.fImageID),
48cb93a386Sopenharmony_ci                   sizeof(fDesc));
49cb93a386Sopenharmony_ci    }
50cb93a386Sopenharmony_ci
51cb93a386Sopenharmony_ci    const SkBitmapCacheDesc fDesc;
52cb93a386Sopenharmony_ci};
53cb93a386Sopenharmony_ci}  // namespace
54cb93a386Sopenharmony_ci
55cb93a386Sopenharmony_ci//////////////////////
56cb93a386Sopenharmony_ci#include "src/core/SkDiscardableMemory.h"
57cb93a386Sopenharmony_ci#include "src/core/SkNextID.h"
58cb93a386Sopenharmony_ci
59cb93a386Sopenharmony_civoid SkBitmapCache_setImmutableWithID(SkPixelRef* pr, uint32_t id) {
60cb93a386Sopenharmony_ci    pr->setImmutableWithID(id);
61cb93a386Sopenharmony_ci}
62cb93a386Sopenharmony_ci
63cb93a386Sopenharmony_ciclass SkBitmapCache::Rec : public SkResourceCache::Rec {
64cb93a386Sopenharmony_cipublic:
65cb93a386Sopenharmony_ci    Rec(const SkBitmapCacheDesc& desc, const SkImageInfo& info, size_t rowBytes,
66cb93a386Sopenharmony_ci        std::unique_ptr<SkDiscardableMemory> dm, void* block)
67cb93a386Sopenharmony_ci        : fKey(desc)
68cb93a386Sopenharmony_ci        , fDM(std::move(dm))
69cb93a386Sopenharmony_ci        , fMalloc(block)
70cb93a386Sopenharmony_ci        , fInfo(info)
71cb93a386Sopenharmony_ci        , fRowBytes(rowBytes)
72cb93a386Sopenharmony_ci    {
73cb93a386Sopenharmony_ci        SkASSERT(!(fDM && fMalloc));    // can't have both
74cb93a386Sopenharmony_ci
75cb93a386Sopenharmony_ci        // We need an ID to return with the bitmap/pixelref. We can't necessarily use the key/desc
76cb93a386Sopenharmony_ci        // ID - lazy images cache the same ID with multiple keys (in different color types).
77cb93a386Sopenharmony_ci        fPrUniqueID = SkNextID::ImageID();
78cb93a386Sopenharmony_ci    }
79cb93a386Sopenharmony_ci
80cb93a386Sopenharmony_ci    ~Rec() override {
81cb93a386Sopenharmony_ci        SkASSERT(0 == fExternalCounter);
82cb93a386Sopenharmony_ci        if (fDM && fDiscardableIsLocked) {
83cb93a386Sopenharmony_ci            SkASSERT(fDM->data());
84cb93a386Sopenharmony_ci            fDM->unlock();
85cb93a386Sopenharmony_ci        }
86cb93a386Sopenharmony_ci        sk_free(fMalloc);   // may be null
87cb93a386Sopenharmony_ci    }
88cb93a386Sopenharmony_ci
89cb93a386Sopenharmony_ci    const Key& getKey() const override { return fKey; }
90cb93a386Sopenharmony_ci    size_t bytesUsed() const override {
91cb93a386Sopenharmony_ci        return sizeof(fKey) + fInfo.computeByteSize(fRowBytes);
92cb93a386Sopenharmony_ci    }
93cb93a386Sopenharmony_ci    bool canBePurged() override {
94cb93a386Sopenharmony_ci        SkAutoMutexExclusive ama(fMutex);
95cb93a386Sopenharmony_ci        return fExternalCounter == 0;
96cb93a386Sopenharmony_ci    }
97cb93a386Sopenharmony_ci    void postAddInstall(void* payload) override {
98cb93a386Sopenharmony_ci        SkAssertResult(this->install(static_cast<SkBitmap*>(payload)));
99cb93a386Sopenharmony_ci    }
100cb93a386Sopenharmony_ci
101cb93a386Sopenharmony_ci    const char* getCategory() const override { return "bitmap"; }
102cb93a386Sopenharmony_ci    SkDiscardableMemory* diagnostic_only_getDiscardable() const override {
103cb93a386Sopenharmony_ci        return fDM.get();
104cb93a386Sopenharmony_ci    }
105cb93a386Sopenharmony_ci
106cb93a386Sopenharmony_ci    static void ReleaseProc(void* addr, void* ctx) {
107cb93a386Sopenharmony_ci        Rec* rec = static_cast<Rec*>(ctx);
108cb93a386Sopenharmony_ci        SkAutoMutexExclusive ama(rec->fMutex);
109cb93a386Sopenharmony_ci
110cb93a386Sopenharmony_ci        SkASSERT(rec->fExternalCounter > 0);
111cb93a386Sopenharmony_ci        rec->fExternalCounter -= 1;
112cb93a386Sopenharmony_ci        if (rec->fDM) {
113cb93a386Sopenharmony_ci            SkASSERT(rec->fMalloc == nullptr);
114cb93a386Sopenharmony_ci            if (rec->fExternalCounter == 0) {
115cb93a386Sopenharmony_ci                rec->fDM->unlock();
116cb93a386Sopenharmony_ci                rec->fDiscardableIsLocked = false;
117cb93a386Sopenharmony_ci            }
118cb93a386Sopenharmony_ci        } else {
119cb93a386Sopenharmony_ci            SkASSERT(rec->fMalloc != nullptr);
120cb93a386Sopenharmony_ci        }
121cb93a386Sopenharmony_ci    }
122cb93a386Sopenharmony_ci
123cb93a386Sopenharmony_ci    bool install(SkBitmap* bitmap) {
124cb93a386Sopenharmony_ci        SkAutoMutexExclusive ama(fMutex);
125cb93a386Sopenharmony_ci
126cb93a386Sopenharmony_ci        if (!fDM && !fMalloc) {
127cb93a386Sopenharmony_ci            return false;
128cb93a386Sopenharmony_ci        }
129cb93a386Sopenharmony_ci
130cb93a386Sopenharmony_ci        if (fDM) {
131cb93a386Sopenharmony_ci            if (!fDiscardableIsLocked) {
132cb93a386Sopenharmony_ci                SkASSERT(fExternalCounter == 0);
133cb93a386Sopenharmony_ci                if (!fDM->lock()) {
134cb93a386Sopenharmony_ci                    fDM.reset(nullptr);
135cb93a386Sopenharmony_ci                    return false;
136cb93a386Sopenharmony_ci                }
137cb93a386Sopenharmony_ci                fDiscardableIsLocked = true;
138cb93a386Sopenharmony_ci            }
139cb93a386Sopenharmony_ci            SkASSERT(fDM->data());
140cb93a386Sopenharmony_ci        }
141cb93a386Sopenharmony_ci
142cb93a386Sopenharmony_ci        bitmap->installPixels(fInfo, fDM ? fDM->data() : fMalloc, fRowBytes, ReleaseProc, this);
143cb93a386Sopenharmony_ci        SkBitmapCache_setImmutableWithID(bitmap->pixelRef(), fPrUniqueID);
144cb93a386Sopenharmony_ci        fExternalCounter++;
145cb93a386Sopenharmony_ci
146cb93a386Sopenharmony_ci        return true;
147cb93a386Sopenharmony_ci    }
148cb93a386Sopenharmony_ci
149cb93a386Sopenharmony_ci    static bool Finder(const SkResourceCache::Rec& baseRec, void* contextBitmap) {
150cb93a386Sopenharmony_ci        Rec* rec = (Rec*)&baseRec;
151cb93a386Sopenharmony_ci        SkBitmap* result = (SkBitmap*)contextBitmap;
152cb93a386Sopenharmony_ci        return rec->install(result);
153cb93a386Sopenharmony_ci    }
154cb93a386Sopenharmony_ci
155cb93a386Sopenharmony_ciprivate:
156cb93a386Sopenharmony_ci    BitmapKey   fKey;
157cb93a386Sopenharmony_ci
158cb93a386Sopenharmony_ci    SkMutex     fMutex;
159cb93a386Sopenharmony_ci
160cb93a386Sopenharmony_ci    // either fDM or fMalloc can be non-null, but not both
161cb93a386Sopenharmony_ci    std::unique_ptr<SkDiscardableMemory> fDM;
162cb93a386Sopenharmony_ci    void*       fMalloc;
163cb93a386Sopenharmony_ci
164cb93a386Sopenharmony_ci    SkImageInfo fInfo;
165cb93a386Sopenharmony_ci    size_t      fRowBytes;
166cb93a386Sopenharmony_ci    uint32_t    fPrUniqueID;
167cb93a386Sopenharmony_ci
168cb93a386Sopenharmony_ci    // This field counts the number of external pixelrefs we have created.
169cb93a386Sopenharmony_ci    // They notify us when they are destroyed so we can decrement this.
170cb93a386Sopenharmony_ci    int  fExternalCounter     = 0;
171cb93a386Sopenharmony_ci    bool fDiscardableIsLocked = true;
172cb93a386Sopenharmony_ci};
173cb93a386Sopenharmony_ci
174cb93a386Sopenharmony_civoid SkBitmapCache::PrivateDeleteRec(Rec* rec) { delete rec; }
175cb93a386Sopenharmony_ci
176cb93a386Sopenharmony_ciSkBitmapCache::RecPtr SkBitmapCache::Alloc(const SkBitmapCacheDesc& desc, const SkImageInfo& info,
177cb93a386Sopenharmony_ci                                           SkPixmap* pmap) {
178cb93a386Sopenharmony_ci    // Ensure that the info matches the subset (i.e. the subset is the entire image)
179cb93a386Sopenharmony_ci    SkASSERT(info.width() == desc.fSubset.width());
180cb93a386Sopenharmony_ci    SkASSERT(info.height() == desc.fSubset.height());
181cb93a386Sopenharmony_ci
182cb93a386Sopenharmony_ci    const size_t rb = info.minRowBytes();
183cb93a386Sopenharmony_ci    size_t size = info.computeByteSize(rb);
184cb93a386Sopenharmony_ci    if (SkImageInfo::ByteSizeOverflowed(size)) {
185cb93a386Sopenharmony_ci        return nullptr;
186cb93a386Sopenharmony_ci    }
187cb93a386Sopenharmony_ci
188cb93a386Sopenharmony_ci    std::unique_ptr<SkDiscardableMemory> dm;
189cb93a386Sopenharmony_ci    void* block = nullptr;
190cb93a386Sopenharmony_ci
191cb93a386Sopenharmony_ci    auto factory = SkResourceCache::GetDiscardableFactory();
192cb93a386Sopenharmony_ci    if (factory) {
193cb93a386Sopenharmony_ci        dm.reset(factory(size));
194cb93a386Sopenharmony_ci    } else {
195cb93a386Sopenharmony_ci        block = sk_malloc_canfail(size);
196cb93a386Sopenharmony_ci    }
197cb93a386Sopenharmony_ci    if (!dm && !block) {
198cb93a386Sopenharmony_ci        return nullptr;
199cb93a386Sopenharmony_ci    }
200cb93a386Sopenharmony_ci    *pmap = SkPixmap(info, dm ? dm->data() : block, rb);
201cb93a386Sopenharmony_ci    return RecPtr(new Rec(desc, info, rb, std::move(dm), block));
202cb93a386Sopenharmony_ci}
203cb93a386Sopenharmony_ci
204cb93a386Sopenharmony_civoid SkBitmapCache::Add(RecPtr rec, SkBitmap* bitmap) {
205cb93a386Sopenharmony_ci    SkResourceCache::Add(rec.release(), bitmap);
206cb93a386Sopenharmony_ci}
207cb93a386Sopenharmony_ci
208cb93a386Sopenharmony_cibool SkBitmapCache::Find(const SkBitmapCacheDesc& desc, SkBitmap* result) {
209cb93a386Sopenharmony_ci    desc.validate();
210cb93a386Sopenharmony_ci    return SkResourceCache::Find(BitmapKey(desc), SkBitmapCache::Rec::Finder, result);
211cb93a386Sopenharmony_ci}
212cb93a386Sopenharmony_ci
213cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////////////////
214cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////////////////
215cb93a386Sopenharmony_ci
216cb93a386Sopenharmony_ci#define CHECK_LOCAL(localCache, localName, globalName, ...) \
217cb93a386Sopenharmony_ci    ((localCache) ? localCache->localName(__VA_ARGS__) : SkResourceCache::globalName(__VA_ARGS__))
218cb93a386Sopenharmony_ci
219cb93a386Sopenharmony_cinamespace {
220cb93a386Sopenharmony_cistatic unsigned gMipMapKeyNamespaceLabel;
221cb93a386Sopenharmony_ci
222cb93a386Sopenharmony_cistruct MipMapKey : public SkResourceCache::Key {
223cb93a386Sopenharmony_cipublic:
224cb93a386Sopenharmony_ci    MipMapKey(const SkBitmapCacheDesc& desc) : fDesc(desc) {
225cb93a386Sopenharmony_ci        this->init(&gMipMapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(fDesc.fImageID),
226cb93a386Sopenharmony_ci                   sizeof(fDesc));
227cb93a386Sopenharmony_ci    }
228cb93a386Sopenharmony_ci
229cb93a386Sopenharmony_ci    const SkBitmapCacheDesc fDesc;
230cb93a386Sopenharmony_ci};
231cb93a386Sopenharmony_ci
232cb93a386Sopenharmony_cistruct MipMapRec : public SkResourceCache::Rec {
233cb93a386Sopenharmony_ci    MipMapRec(const SkBitmapCacheDesc& desc, const SkMipmap* result)
234cb93a386Sopenharmony_ci        : fKey(desc)
235cb93a386Sopenharmony_ci        , fMipMap(result)
236cb93a386Sopenharmony_ci    {
237cb93a386Sopenharmony_ci        fMipMap->attachToCacheAndRef();
238cb93a386Sopenharmony_ci    }
239cb93a386Sopenharmony_ci
240cb93a386Sopenharmony_ci    ~MipMapRec() override {
241cb93a386Sopenharmony_ci        fMipMap->detachFromCacheAndUnref();
242cb93a386Sopenharmony_ci    }
243cb93a386Sopenharmony_ci
244cb93a386Sopenharmony_ci    const Key& getKey() const override { return fKey; }
245cb93a386Sopenharmony_ci    size_t bytesUsed() const override { return sizeof(fKey) + fMipMap->size(); }
246cb93a386Sopenharmony_ci    const char* getCategory() const override { return "mipmap"; }
247cb93a386Sopenharmony_ci    SkDiscardableMemory* diagnostic_only_getDiscardable() const override {
248cb93a386Sopenharmony_ci        return fMipMap->diagnostic_only_getDiscardable();
249cb93a386Sopenharmony_ci    }
250cb93a386Sopenharmony_ci
251cb93a386Sopenharmony_ci    static bool Finder(const SkResourceCache::Rec& baseRec, void* contextMip) {
252cb93a386Sopenharmony_ci        const MipMapRec& rec = static_cast<const MipMapRec&>(baseRec);
253cb93a386Sopenharmony_ci        const SkMipmap* mm = SkRef(rec.fMipMap);
254cb93a386Sopenharmony_ci        // the call to ref() above triggers a "lock" in the case of discardable memory,
255cb93a386Sopenharmony_ci        // which means we can now check for null (in case the lock failed).
256cb93a386Sopenharmony_ci        if (nullptr == mm->data()) {
257cb93a386Sopenharmony_ci            mm->unref();    // balance our call to ref()
258cb93a386Sopenharmony_ci            return false;
259cb93a386Sopenharmony_ci        }
260cb93a386Sopenharmony_ci        // the call must call unref() when they are done.
261cb93a386Sopenharmony_ci        *(const SkMipmap**)contextMip = mm;
262cb93a386Sopenharmony_ci        return true;
263cb93a386Sopenharmony_ci    }
264cb93a386Sopenharmony_ci
265cb93a386Sopenharmony_ciprivate:
266cb93a386Sopenharmony_ci    MipMapKey       fKey;
267cb93a386Sopenharmony_ci    const SkMipmap* fMipMap;
268cb93a386Sopenharmony_ci};
269cb93a386Sopenharmony_ci}  // namespace
270cb93a386Sopenharmony_ci
271cb93a386Sopenharmony_ciconst SkMipmap* SkMipmapCache::FindAndRef(const SkBitmapCacheDesc& desc,
272cb93a386Sopenharmony_ci                                          SkResourceCache* localCache) {
273cb93a386Sopenharmony_ci    MipMapKey key(desc);
274cb93a386Sopenharmony_ci    const SkMipmap* result;
275cb93a386Sopenharmony_ci
276cb93a386Sopenharmony_ci    if (!CHECK_LOCAL(localCache, find, Find, key, MipMapRec::Finder, &result)) {
277cb93a386Sopenharmony_ci        result = nullptr;
278cb93a386Sopenharmony_ci    }
279cb93a386Sopenharmony_ci    return result;
280cb93a386Sopenharmony_ci}
281cb93a386Sopenharmony_ci
282cb93a386Sopenharmony_cistatic SkResourceCache::DiscardableFactory get_fact(SkResourceCache* localCache) {
283cb93a386Sopenharmony_ci    return localCache ? localCache->discardableFactory()
284cb93a386Sopenharmony_ci                      : SkResourceCache::GetDiscardableFactory();
285cb93a386Sopenharmony_ci}
286cb93a386Sopenharmony_ci
287cb93a386Sopenharmony_ciconst SkMipmap* SkMipmapCache::AddAndRef(const SkImage_Base* image, SkResourceCache* localCache) {
288cb93a386Sopenharmony_ci    SkBitmap src;
289cb93a386Sopenharmony_ci    if (!image->getROPixels(nullptr, &src)) {
290cb93a386Sopenharmony_ci        return nullptr;
291cb93a386Sopenharmony_ci    }
292cb93a386Sopenharmony_ci
293cb93a386Sopenharmony_ci    SkMipmap* mipmap = SkMipmap::Build(src, get_fact(localCache));
294cb93a386Sopenharmony_ci    if (mipmap) {
295cb93a386Sopenharmony_ci        MipMapRec* rec = new MipMapRec(SkBitmapCacheDesc::Make(image), mipmap);
296cb93a386Sopenharmony_ci        CHECK_LOCAL(localCache, add, Add, rec);
297cb93a386Sopenharmony_ci        image->notifyAddedToRasterCache();
298cb93a386Sopenharmony_ci    }
299cb93a386Sopenharmony_ci    return mipmap;
300cb93a386Sopenharmony_ci}
301