SkResourceCache.h revision 790ffe3feb90370318f42b28eb9c6af6e38cd4f9
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 8#ifndef SkResourceCache_DEFINED 9#define SkResourceCache_DEFINED 10 11#include "SkBitmap.h" 12 13class SkDiscardableMemory; 14class SkMipMap; 15 16/** 17 * Cache object for bitmaps (with possible scale in X Y as part of the key). 18 * 19 * Multiple caches can be instantiated, but each instance is not implicitly 20 * thread-safe, so if a given instance is to be shared across threads, the 21 * caller must manage the access itself (e.g. via a mutex). 22 * 23 * As a convenience, a global instance is also defined, which can be safely 24 * access across threads via the static methods (e.g. FindAndLock, etc.). 25 */ 26class SkResourceCache { 27public: 28 struct Key { 29 // Call this to access your private contents. Must not use the address after calling init() 30 void* writableContents() { return this + 1; } 31 32 // must call this after your private data has been written. 33 // length must be a multiple of 4 34 void init(size_t length); 35 36 // This is only valid after having called init(). 37 uint32_t hash() const { return fHash; } 38 39 bool operator==(const Key& other) const { 40 const uint32_t* a = this->as32(); 41 const uint32_t* b = other.as32(); 42 for (int i = 0; i < fCount32; ++i) { 43 if (a[i] != b[i]) { 44 return false; 45 } 46 } 47 return true; 48 } 49 50 private: 51 // store fCount32 first, so we don't consider it in operator< 52 int32_t fCount32; // 2 + user contents count32 53 uint32_t fHash; 54 /* uint32_t fContents32[] */ 55 56 const uint32_t* as32() const { return (const uint32_t*)this; } 57 const uint32_t* as32SkipCount() const { return this->as32() + 1; } 58 }; 59 60 struct Rec { 61 typedef SkResourceCache::Key Key; 62 63 Rec() : fLockCount(1) {} 64 virtual ~Rec() {} 65 66 uint32_t getHash() const { return this->getKey().hash(); } 67 68 virtual const Key& getKey() const = 0; 69 virtual size_t bytesUsed() const = 0; 70 71 // for SkTDynamicHash::Traits 72 static uint32_t Hash(const Key& key) { return key.hash(); } 73 static const Key& GetKey(const Rec& rec) { return rec.getKey(); } 74 75 private: 76 Rec* fNext; 77 Rec* fPrev; 78 int32_t fLockCount; 79 80 friend class SkResourceCache; 81 }; 82 83 typedef const Rec* ID; 84 85 /** 86 * Returns a locked/pinned SkDiscardableMemory instance for the specified 87 * number of bytes, or NULL on failure. 88 */ 89 typedef SkDiscardableMemory* (*DiscardableFactory)(size_t bytes); 90 91 /* 92 * The following static methods are thread-safe wrappers around a global 93 * instance of this cache. 94 */ 95 96 static const Rec* FindAndLock(const Key& key); 97 static const Rec* AddAndLock(Rec*); 98 static void Add(Rec*); 99 static void Unlock(ID); 100 static void Remove(ID); 101 102 static size_t GetTotalBytesUsed(); 103 static size_t GetTotalByteLimit(); 104 static size_t SetTotalByteLimit(size_t newLimit); 105 106 static size_t SetSingleAllocationByteLimit(size_t); 107 static size_t GetSingleAllocationByteLimit(); 108 109 /** 110 * Use this allocator for bitmaps, so they can use ashmem when available. 111 * Returns NULL if the ResourceCache has not been initialized with a DiscardableFactory. 112 */ 113 static SkBitmap::Allocator* GetAllocator(); 114 115 /** 116 * Call SkDebugf() with diagnostic information about the state of the cache 117 */ 118 static void Dump(); 119 120 /////////////////////////////////////////////////////////////////////////// 121 122 /** 123 * Construct the cache to call DiscardableFactory when it 124 * allocates memory for the pixels. In this mode, the cache has 125 * not explicit budget, and so methods like getTotalBytesUsed() 126 * and getTotalByteLimit() will return 0, and setTotalByteLimit 127 * will ignore its argument and return 0. 128 */ 129 SkResourceCache(DiscardableFactory); 130 131 /** 132 * Construct the cache, allocating memory with malloc, and respect the 133 * byteLimit, purging automatically when a new image is added to the cache 134 * that pushes the total bytesUsed over the limit. Note: The limit can be 135 * changed at runtime with setTotalByteLimit. 136 */ 137 explicit SkResourceCache(size_t byteLimit); 138 ~SkResourceCache(); 139 140 const Rec* findAndLock(const Key& key); 141 const Rec* addAndLock(Rec*); 142 void add(Rec*); 143 void remove(Rec*); 144 145 /** 146 * Given a non-null ID ptr returned by either findAndLock or addAndLock, 147 * this releases the associated resources to be available to be purged 148 * if needed. After this, the cached bitmap should no longer be 149 * referenced by the caller. 150 */ 151 void unlock(ID); 152 153 size_t getTotalBytesUsed() const { return fTotalBytesUsed; } 154 size_t getTotalByteLimit() const { return fTotalByteLimit; } 155 156 /** 157 * This is respected by SkBitmapProcState::possiblyScaleImage. 158 * 0 is no maximum at all; this is the default. 159 * setSingleAllocationByteLimit() returns the previous value. 160 */ 161 size_t setSingleAllocationByteLimit(size_t maximumAllocationSize); 162 size_t getSingleAllocationByteLimit() const; 163 /** 164 * Set the maximum number of bytes available to this cache. If the current 165 * cache exceeds this new value, it will be purged to try to fit within 166 * this new limit. 167 */ 168 size_t setTotalByteLimit(size_t newLimit); 169 170 SkBitmap::Allocator* allocator() const { return fAllocator; }; 171 172 /** 173 * Call SkDebugf() with diagnostic information about the state of the cache 174 */ 175 void dump() const; 176 177private: 178 Rec* fHead; 179 Rec* fTail; 180 181 class Hash; 182 Hash* fHash; 183 184 DiscardableFactory fDiscardableFactory; 185 // the allocator is NULL or one that matches discardables 186 SkBitmap::Allocator* fAllocator; 187 188 size_t fTotalBytesUsed; 189 size_t fTotalByteLimit; 190 size_t fSingleAllocationByteLimit; 191 int fCount; 192 193 void purgeAsNeeded(); 194 195 // linklist management 196 void moveToHead(Rec*); 197 void addToHead(Rec*); 198 void detach(Rec*); 199 200 void init(); // called by constructors 201 202#ifdef SK_DEBUG 203 void validate() const; 204#else 205 void validate() const {} 206#endif 207}; 208#endif 209