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