• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3  * Copyright 2012 Google Inc.
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 #ifndef SkBitmapHeap_DEFINED
9 #define SkBitmapHeap_DEFINED
10 
11 #include "SkBitmap.h"
12 #include "SkFlattenable.h"
13 #include "SkRefCnt.h"
14 #include "SkTDArray.h"
15 #include "SkThread.h"
16 #include "SkTRefArray.h"
17 
18 /**
19  * SkBitmapHeapEntry provides users of SkBitmapHeap (using internal storage) with a means to...
20  *  (1) get access a bitmap in the heap
21  *  (2) indicate they are done with bitmap by releasing their reference (if they were an owner).
22  */
23 class SkBitmapHeapEntry : SkNoncopyable {
24 public:
25     ~SkBitmapHeapEntry();
26 
getSlot()27     int32_t getSlot() { return fSlot; }
28 
getBitmap()29     SkBitmap* getBitmap() { return &fBitmap; }
30 
releaseRef()31     void releaseRef() {
32         sk_atomic_dec(&fRefCount);
33     }
34 
35 private:
36     SkBitmapHeapEntry();
37 
38     void addReferences(int count);
39 
40     int32_t fSlot;
41     int32_t fRefCount;
42 
43     SkBitmap fBitmap;
44     // Keep track of the bytes allocated for this bitmap. When replacing the
45     // bitmap or removing this HeapEntry we know how much memory has been
46     // reclaimed.
47     size_t fBytesAllocated;
48 
49     friend class SkBitmapHeap;
50     friend class SkBitmapHeapTester;
51 };
52 
53 
54 class SkBitmapHeapReader : public SkRefCnt {
55 public:
SK_DECLARE_INST_COUNT(SkBitmapHeapReader)56     SK_DECLARE_INST_COUNT(SkBitmapHeapReader)
57 
58     SkBitmapHeapReader() : INHERITED() {}
59     virtual SkBitmap* getBitmap(int32_t slot) const = 0;
60     virtual void releaseRef(int32_t slot) = 0;
61 private:
62     typedef SkRefCnt INHERITED;
63 };
64 
65 
66 /**
67  * TODO: stores immutable bitmaps into a heap
68  */
69 class SkBitmapHeap : public SkBitmapHeapReader {
70 public:
71     class ExternalStorage : public SkRefCnt {
72      public:
73         SK_DECLARE_INST_COUNT(ExternalStorage)
74 
75         virtual bool insert(const SkBitmap& bitmap, int32_t slot) = 0;
76 
77      private:
78         typedef SkRefCnt INHERITED;
79     };
80 
81     static const int32_t UNLIMITED_SIZE = -1;
82     static const int32_t IGNORE_OWNERS  = -1;
83     static const int32_t INVALID_SLOT   = -1;
84 
85     /**
86      * Constructs a heap that is responsible for allocating and managing its own storage.  In the
87      * case where we choose to allow the heap to grow indefinitely (i.e. UNLIMITED_SIZE) we
88      * guarantee that once allocated in the heap a bitmap's index in the heap is immutable.
89      * Otherwise we guarantee the bitmaps placement in the heap until its owner count goes to zero.
90      *
91      * @param preferredSize  Specifies the preferred maximum number of bitmaps to store. This is
92      *   not a hard limit as it can grow larger if the number of bitmaps in the heap with active
93      *   owners exceeds this limit.
94      * @param ownerCount  The number of owners to assign to each inserted bitmap. NOTE: while a
95      *   bitmap in the heap has a least one owner it can't be removed.
96      */
97     SkBitmapHeap(int32_t preferredSize = UNLIMITED_SIZE, int32_t ownerCount = IGNORE_OWNERS);
98 
99     /**
100      * Constructs a heap that defers the responsibility of storing the bitmaps to an external
101      * function. This is especially useful if the bitmaps will be used in a separate process as the
102      * external storage can ensure the data is properly shuttled to the appropriate processes.
103      *
104      * Our LRU implementation assumes that inserts into the external storage are consumed in the
105      * order that they are inserted (i.e. SkPipe). This ensures that we don't need to query the
106      * external storage to see if a slot in the heap is eligible to be overwritten.
107      *
108      * @param externalStorage  The class responsible for storing the bitmaps inserted into the heap
109      * @param heapSize  The maximum size of the heap. Because of the sequential limitation imposed
110      *   by our LRU implementation we can guarantee that the heap will never grow beyond this size.
111      */
112     SkBitmapHeap(ExternalStorage* externalStorage, int32_t heapSize = UNLIMITED_SIZE);
113 
114     ~SkBitmapHeap();
115 
116     /**
117      * Makes a shallow copy of all bitmaps currently in the heap and returns them as an array. The
118      * array indices match their position in the heap.
119      *
120      * @return  a ptr to an array of bitmaps or NULL if external storage is being used.
121      */
122     SkTRefArray<SkBitmap>* extractBitmaps() const;
123 
124     /**
125      * Retrieves the bitmap from the specified slot in the heap
126      *
127      * @return  The bitmap located at that slot or NULL if external storage is being used.
128      */
getBitmap(int32_t slot)129     virtual SkBitmap* getBitmap(int32_t slot) const SK_OVERRIDE {
130         SkASSERT(fExternalStorage == NULL);
131         SkBitmapHeapEntry* entry = getEntry(slot);
132         if (entry) {
133             return &entry->fBitmap;
134         }
135         return NULL;
136     }
137 
138     /**
139      * Retrieves the bitmap from the specified slot in the heap
140      *
141      * @return  The bitmap located at that slot or NULL if external storage is being used.
142      */
releaseRef(int32_t slot)143     virtual void releaseRef(int32_t slot) SK_OVERRIDE {
144         SkASSERT(fExternalStorage == NULL);
145         if (fOwnerCount != IGNORE_OWNERS) {
146             SkBitmapHeapEntry* entry = getEntry(slot);
147             if (entry) {
148                 entry->releaseRef();
149             }
150         }
151     }
152 
153     /**
154      * Inserts a bitmap into the heap. The stored version of bitmap is guaranteed to be immutable
155      * and is not dependent on the lifecycle of the provided bitmap.
156      *
157      * @param bitmap  the bitmap to be inserted into the heap
158      * @return  the slot in the heap where the bitmap is stored or INVALID_SLOT if the bitmap could
159      *          not be added to the heap. If it was added the slot will remain valid...
160      *            (1) indefinitely if no owner count has been specified.
161      *            (2) until all owners have called releaseRef on the appropriate SkBitmapHeapEntry*
162      */
163     int32_t insert(const SkBitmap& bitmap);
164 
165     /**
166      * Retrieves an entry from the heap at a given slot.
167      *
168      * @param slot  the slot in the heap where a bitmap was stored.
169      * @return  a SkBitmapHeapEntry that wraps the bitmap or NULL if external storage is used.
170      */
getEntry(int32_t slot)171     SkBitmapHeapEntry* getEntry(int32_t slot) const {
172         SkASSERT(slot <= fStorage.count());
173         if (fExternalStorage != NULL) {
174             return NULL;
175         }
176         return fStorage[slot];
177     }
178 
179     /**
180      * Returns a count of the number of items currently in the heap
181      */
count()182     int count() const {
183         SkASSERT(fExternalStorage != NULL ||
184                  fStorage.count() - fUnusedSlots.count() == fLookupTable.count());
185         return fLookupTable.count();
186     }
187 
188     /**
189      * Returns the total number of bytes allocated by the bitmaps in the heap
190      */
bytesAllocated()191     size_t bytesAllocated() const {
192         return fBytesAllocated;
193     }
194 
195     /**
196      * Attempt to reduce the storage allocated.
197      * @param bytesToFree minimum number of bytes that should be attempted to
198      *   be freed.
199      * @return number of bytes actually freed.
200      */
201     size_t freeMemoryIfPossible(size_t bytesToFree);
202 
203     /**
204      * Defer any increments of owner counts until endAddingOwnersDeferral is called. So if an
205      * existing SkBitmap is inserted into the SkBitmapHeap, its corresponding SkBitmapHeapEntry will
206      * not have addReferences called on it, and the client does not need to make a corresponding
207      * call to releaseRef. Only meaningful if this SkBitmapHeap was created with an owner count not
208      * equal to IGNORE_OWNERS.
209      */
210     void deferAddingOwners();
211 
212     /**
213      * Resume adding references when duplicate SkBitmaps are inserted.
214      * @param add If true, add references to the SkBitmapHeapEntrys whose SkBitmaps were re-inserted
215      *            while deferring.
216      */
217     void endAddingOwnersDeferral(bool add);
218 
219 private:
220     struct LookupEntry {
LookupEntryLookupEntry221         LookupEntry(const SkBitmap& bm)
222         : fGenerationId(bm.getGenerationID())
223         , fPixelOffset(bm.pixelRefOffset())
224         , fWidth(bm.width())
225         , fHeight(bm.height())
226         , fMoreRecentlyUsed(NULL)
227         , fLessRecentlyUsed(NULL){}
228 
229         const uint32_t fGenerationId; // SkPixelRef GenerationID.
230         const size_t   fPixelOffset;
231         const uint32_t fWidth;
232         const uint32_t fHeight;
233 
234         // TODO: Generalize the LRU caching mechanism
235         LookupEntry* fMoreRecentlyUsed;
236         LookupEntry* fLessRecentlyUsed;
237 
238         uint32_t fStorageSlot; // slot of corresponding bitmap in fStorage.
239 
240         /**
241          * Compare two LookupEntry pointers, returning -1, 0, 1 for sorting.
242          */
243         static int Compare(const LookupEntry* a, const LookupEntry* b);
244     };
245 
246     /**
247      * Remove the entry from the lookup table. Also deletes the entry pointed
248      * to by the table. Therefore, if a pointer to that one was passed in, the
249      * pointer should no longer be used, since the object to which it points has
250      * been deleted.
251      * @return The index in the lookup table of the entry before removal.
252      */
253     int removeEntryFromLookupTable(LookupEntry*);
254 
255     /**
256      * Searches for the bitmap in the lookup table and returns the bitmaps index within the table.
257      * If the bitmap was not already in the table it is added.
258      *
259      * @param key    The key to search the lookup table, created from a bitmap.
260      * @param entry  A pointer to a SkBitmapHeapEntry* that if non-null AND the bitmap is found
261      *               in the lookup table is populated with the entry from the heap storage.
262      */
263     int findInLookupTable(const LookupEntry& key, SkBitmapHeapEntry** entry);
264 
265     LookupEntry* findEntryToReplace(const SkBitmap& replacement);
266     bool copyBitmap(const SkBitmap& originalBitmap, SkBitmap& copiedBitmap);
267 
268     /**
269      * Remove a LookupEntry from the LRU, in preparation for either deleting or appending as most
270      * recent. Points the LookupEntry's old neighbors at each other, and sets fLeastRecentlyUsed
271      * (if there is still an entry left). Sets LookupEntry's fMoreRecentlyUsed to NULL and leaves
272      * its fLessRecentlyUsed unmodified.
273      */
274     void removeFromLRU(LookupEntry* entry);
275 
276     /**
277      * Append a LookupEntry to the end of the LRU cache, marking it as the most
278      * recently used. Assumes that the LookupEntry is already in fLookupTable,
279      * but is not in the LRU cache. If it is in the cache, removeFromLRU should
280      * be called first.
281      */
282     void appendToLRU(LookupEntry*);
283 
284     // searchable index that maps to entries in the heap
285     SkTDArray<LookupEntry*> fLookupTable;
286 
287     // heap storage
288     SkTDArray<SkBitmapHeapEntry*> fStorage;
289     // Used to mark slots in fStorage as deleted without actually deleting
290     // the slot so as not to mess up the numbering.
291     SkTDArray<int> fUnusedSlots;
292     ExternalStorage* fExternalStorage;
293 
294     LookupEntry* fMostRecentlyUsed;
295     LookupEntry* fLeastRecentlyUsed;
296 
297     const int32_t fPreferredCount;
298     const int32_t fOwnerCount;
299     size_t fBytesAllocated;
300 
301     bool fDeferAddingOwners;
302     SkTDArray<int> fDeferredEntries;
303 
304     typedef SkBitmapHeapReader INHERITED;
305 };
306 
307 #endif // SkBitmapHeap_DEFINED
308