SkBitmapCache.cpp 9.4 KB

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