SkResourceCache.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. /*
  2. * Copyright 2013 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. #ifndef SkResourceCache_DEFINED
  8. #define SkResourceCache_DEFINED
  9. #include "include/core/SkBitmap.h"
  10. #include "include/private/SkTDArray.h"
  11. #include "src/core/SkMessageBus.h"
  12. class SkCachedData;
  13. class SkDiscardableMemory;
  14. class SkTraceMemoryDump;
  15. /**
  16. * Cache object for bitmaps (with possible scale in X Y as part of the key).
  17. *
  18. * Multiple caches can be instantiated, but each instance is not implicitly
  19. * thread-safe, so if a given instance is to be shared across threads, the
  20. * caller must manage the access itself (e.g. via a mutex).
  21. *
  22. * As a convenience, a global instance is also defined, which can be safely
  23. * access across threads via the static methods (e.g. FindAndLock, etc.).
  24. */
  25. class SkResourceCache {
  26. public:
  27. struct Key {
  28. /** Key subclasses must call this after their own fields and data are initialized.
  29. * All fields and data must be tightly packed.
  30. * @param nameSpace must be unique per Key subclass.
  31. * @param sharedID == 0 means ignore this field, does not support group purging.
  32. * @param dataSize is size of fields and data of the subclass, must be a multiple of 4.
  33. */
  34. void init(void* nameSpace, uint64_t sharedID, size_t dataSize);
  35. /** Returns the size of this key. */
  36. size_t size() const {
  37. return fCount32 << 2;
  38. }
  39. void* getNamespace() const { return fNamespace; }
  40. uint64_t getSharedID() const { return ((uint64_t)fSharedID_hi << 32) | fSharedID_lo; }
  41. // This is only valid after having called init().
  42. uint32_t hash() const { return fHash; }
  43. bool operator==(const Key& other) const {
  44. const uint32_t* a = this->as32();
  45. const uint32_t* b = other.as32();
  46. for (int i = 0; i < fCount32; ++i) { // (This checks fCount == other.fCount first.)
  47. if (a[i] != b[i]) {
  48. return false;
  49. }
  50. }
  51. return true;
  52. }
  53. private:
  54. int32_t fCount32; // local + user contents count32
  55. uint32_t fHash;
  56. // split uint64_t into hi and lo so we don't force ourselves to pad on 32bit machines.
  57. uint32_t fSharedID_lo;
  58. uint32_t fSharedID_hi;
  59. void* fNamespace; // A unique namespace tag. This is hashed.
  60. /* uint32_t fContents32[] */
  61. const uint32_t* as32() const { return (const uint32_t*)this; }
  62. };
  63. struct Rec {
  64. typedef SkResourceCache::Key Key;
  65. Rec() {}
  66. virtual ~Rec() {}
  67. uint32_t getHash() const { return this->getKey().hash(); }
  68. virtual const Key& getKey() const = 0;
  69. virtual size_t bytesUsed() const = 0;
  70. // Called if the cache needs to purge/remove/delete the Rec. Default returns true.
  71. // Subclass may return false if there are outstanding references to it (e.g. bitmaps).
  72. // Will only be deleted/removed-from-the-cache when this returns true.
  73. virtual bool canBePurged() { return true; }
  74. // A rec is first created/initialized, and then added to the cache. As part of the add(),
  75. // the cache will callback into the rec with postAddInstall, passing in whatever payload
  76. // was passed to add/Add.
  77. //
  78. // This late-install callback exists because the process of add-ing might end up deleting
  79. // the new rec (if an existing rec in the cache has the same key and cannot be purged).
  80. // If the new rec will be deleted during add, the pre-existing one (with the same key)
  81. // will have postAddInstall() called on it instead, so that either way an "install" will
  82. // happen during the add.
  83. virtual void postAddInstall(void*) {}
  84. // for memory usage diagnostics
  85. virtual const char* getCategory() const = 0;
  86. virtual SkDiscardableMemory* diagnostic_only_getDiscardable() const { return nullptr; }
  87. private:
  88. Rec* fNext;
  89. Rec* fPrev;
  90. friend class SkResourceCache;
  91. };
  92. // Used with SkMessageBus
  93. struct PurgeSharedIDMessage {
  94. PurgeSharedIDMessage(uint64_t sharedID) : fSharedID(sharedID) {}
  95. uint64_t fSharedID;
  96. };
  97. typedef const Rec* ID;
  98. /**
  99. * Callback function for find(). If called, the cache will have found a match for the
  100. * specified Key, and will pass in the corresponding Rec, along with a caller-specified
  101. * context. The function can read the data in Rec, and copy whatever it likes into context
  102. * (casting context to whatever it really is).
  103. *
  104. * The return value determines what the cache will do with the Rec. If the function returns
  105. * true, then the Rec is considered "valid". If false is returned, the Rec will be considered
  106. * "stale" and will be purged from the cache.
  107. */
  108. typedef bool (*FindVisitor)(const Rec&, void* context);
  109. /**
  110. * Returns a locked/pinned SkDiscardableMemory instance for the specified
  111. * number of bytes, or nullptr on failure.
  112. */
  113. typedef SkDiscardableMemory* (*DiscardableFactory)(size_t bytes);
  114. /*
  115. * The following static methods are thread-safe wrappers around a global
  116. * instance of this cache.
  117. */
  118. /**
  119. * Returns true if the visitor was called on a matching Key, and the visitor returned true.
  120. *
  121. * Find() will search the cache for the specified Key. If no match is found, return false and
  122. * do not call the FindVisitor. If a match is found, return whatever the visitor returns.
  123. * Its return value is interpreted to mean:
  124. * true : Rec is valid
  125. * false : Rec is "stale" -- the cache will purge it.
  126. */
  127. static bool Find(const Key& key, FindVisitor, void* context);
  128. static void Add(Rec*, void* payload = nullptr);
  129. typedef void (*Visitor)(const Rec&, void* context);
  130. // Call the visitor for every Rec in the cache.
  131. static void VisitAll(Visitor, void* context);
  132. static size_t GetTotalBytesUsed();
  133. static size_t GetTotalByteLimit();
  134. static size_t SetTotalByteLimit(size_t newLimit);
  135. static size_t SetSingleAllocationByteLimit(size_t);
  136. static size_t GetSingleAllocationByteLimit();
  137. static size_t GetEffectiveSingleAllocationByteLimit();
  138. static void PurgeAll();
  139. static void TestDumpMemoryStatistics();
  140. /** Dump memory usage statistics of every Rec in the cache using the
  141. SkTraceMemoryDump interface.
  142. */
  143. static void DumpMemoryStatistics(SkTraceMemoryDump* dump);
  144. /**
  145. * Returns the DiscardableFactory used by the global cache, or nullptr.
  146. */
  147. static DiscardableFactory GetDiscardableFactory();
  148. static SkCachedData* NewCachedData(size_t bytes);
  149. static void PostPurgeSharedID(uint64_t sharedID);
  150. /**
  151. * Call SkDebugf() with diagnostic information about the state of the cache
  152. */
  153. static void Dump();
  154. ///////////////////////////////////////////////////////////////////////////
  155. /**
  156. * Construct the cache to call DiscardableFactory when it
  157. * allocates memory for the pixels. In this mode, the cache has
  158. * not explicit budget, and so methods like getTotalBytesUsed()
  159. * and getTotalByteLimit() will return 0, and setTotalByteLimit
  160. * will ignore its argument and return 0.
  161. */
  162. SkResourceCache(DiscardableFactory);
  163. /**
  164. * Construct the cache, allocating memory with malloc, and respect the
  165. * byteLimit, purging automatically when a new image is added to the cache
  166. * that pushes the total bytesUsed over the limit. Note: The limit can be
  167. * changed at runtime with setTotalByteLimit.
  168. */
  169. explicit SkResourceCache(size_t byteLimit);
  170. ~SkResourceCache();
  171. /**
  172. * Returns true if the visitor was called on a matching Key, and the visitor returned true.
  173. *
  174. * find() will search the cache for the specified Key. If no match is found, return false and
  175. * do not call the FindVisitor. If a match is found, return whatever the visitor returns.
  176. * Its return value is interpreted to mean:
  177. * true : Rec is valid
  178. * false : Rec is "stale" -- the cache will purge it.
  179. */
  180. bool find(const Key&, FindVisitor, void* context);
  181. void add(Rec*, void* payload = nullptr);
  182. void visitAll(Visitor, void* context);
  183. size_t getTotalBytesUsed() const { return fTotalBytesUsed; }
  184. size_t getTotalByteLimit() const { return fTotalByteLimit; }
  185. /**
  186. * This is respected by SkBitmapProcState::possiblyScaleImage.
  187. * 0 is no maximum at all; this is the default.
  188. * setSingleAllocationByteLimit() returns the previous value.
  189. */
  190. size_t setSingleAllocationByteLimit(size_t maximumAllocationSize);
  191. size_t getSingleAllocationByteLimit() const;
  192. // returns the logical single allocation size (pinning against the budget when the cache
  193. // is not backed by discardable memory.
  194. size_t getEffectiveSingleAllocationByteLimit() const;
  195. /**
  196. * Set the maximum number of bytes available to this cache. If the current
  197. * cache exceeds this new value, it will be purged to try to fit within
  198. * this new limit.
  199. */
  200. size_t setTotalByteLimit(size_t newLimit);
  201. void purgeSharedID(uint64_t sharedID);
  202. void purgeAll() {
  203. this->purgeAsNeeded(true);
  204. }
  205. DiscardableFactory discardableFactory() const { return fDiscardableFactory; }
  206. SkCachedData* newCachedData(size_t bytes);
  207. /**
  208. * Call SkDebugf() with diagnostic information about the state of the cache
  209. */
  210. void dump() const;
  211. private:
  212. Rec* fHead;
  213. Rec* fTail;
  214. class Hash;
  215. Hash* fHash;
  216. DiscardableFactory fDiscardableFactory;
  217. size_t fTotalBytesUsed;
  218. size_t fTotalByteLimit;
  219. size_t fSingleAllocationByteLimit;
  220. int fCount;
  221. SkMessageBus<PurgeSharedIDMessage>::Inbox fPurgeSharedIDInbox;
  222. void checkMessages();
  223. void purgeAsNeeded(bool forcePurge = false);
  224. // linklist management
  225. void moveToHead(Rec*);
  226. void addToHead(Rec*);
  227. void release(Rec*);
  228. void remove(Rec*);
  229. void init(); // called by constructors
  230. #ifdef SK_DEBUG
  231. void validate() const;
  232. #else
  233. void validate() const {}
  234. #endif
  235. };
  236. #endif