SkBitmapHeap.h revision 21830d90096d2dccc4168d99a427e78035ce942a
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 */
23class SkBitmapHeapEntry : SkNoncopyable {
24public:
25    ~SkBitmapHeapEntry();
26
27    int32_t getSlot() { return fSlot; }
28
29    SkBitmap* getBitmap() { return &fBitmap; }
30
31    void releaseRef() {
32        sk_atomic_dec(&fRefCount);
33    }
34
35private:
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    // TODO: Generalize the LRU caching mechanism
49    SkBitmapHeapEntry* fMoreRecentlyUsed;
50    SkBitmapHeapEntry* fLessRecentlyUsed;
51
52    friend class SkBitmapHeap;
53};
54
55
56class SkBitmapHeapReader : public SkRefCnt {
57public:
58    SkBitmapHeapReader() : INHERITED() {}
59    virtual SkBitmap* getBitmap(int32_t slot) const = 0;
60    virtual void releaseRef(int32_t slot) = 0;
61private:
62    typedef SkRefCnt INHERITED;
63};
64
65
66/**
67 * TODO: stores immutable bitmaps into a heap
68 */
69class SkBitmapHeap : public SkBitmapHeapReader {
70public:
71    class ExternalStorage : public SkRefCnt {
72     public:
73        virtual bool insert(const SkBitmap& bitmap, int32_t slot) = 0;
74    };
75
76    static const int32_t UNLIMITED_SIZE = -1;
77    static const int32_t IGNORE_OWNERS  = -1;
78    static const int32_t INVALID_SLOT   = -1;
79
80    /**
81     * Constructs a heap that is responsible for allocating and managing its own storage.  In the
82     * case where we choose to allow the heap to grow indefinitely (i.e. UNLIMITED_SIZE) we
83     * guarantee that once allocated in the heap a bitmap's index in the heap is immutable.
84     * Otherwise we guarantee the bitmaps placement in the heap until its owner count goes to zero.
85     *
86     * @param preferredSize  Specifies the preferred maximum number of bitmaps to store. This is
87     *   not a hard limit as it can grow larger if the number of bitmaps in the heap with active
88     *   owners exceeds this limit.
89     * @param ownerCount  The number of owners to assign to each inserted bitmap. NOTE: while a
90     *   bitmap in the heap has a least one owner it can't be removed.
91     */
92    SkBitmapHeap(int32_t preferredSize = UNLIMITED_SIZE, int32_t ownerCount = IGNORE_OWNERS);
93
94    /**
95     * Constructs a heap that defers the responsibility of storing the bitmaps to an external
96     * function. This is especially useful if the bitmaps will be used in a separate process as the
97     * external storage can ensure the data is properly shuttled to the appropriate processes.
98     *
99     * Our LRU implementation assumes that inserts into the external storage are consumed in the
100     * order that they are inserted (i.e. SkPipe). This ensures that we don't need to query the
101     * external storage to see if a slot in the heap is eligible to be overwritten.
102     *
103     * @param externalStorage  The class responsible for storing the bitmaps inserted into the heap
104     * @param heapSize  The maximum size of the heap. Because of the sequential limitation imposed
105     *   by our LRU implementation we can guarantee that the heap will never grow beyond this size.
106     */
107    SkBitmapHeap(ExternalStorage* externalStorage, int32_t heapSize = UNLIMITED_SIZE);
108
109    ~SkBitmapHeap();
110
111    /**
112     * Makes a shallow copy of all bitmaps currently in the heap and returns them as an array. The
113     * array indices match their position in the heap.
114     *
115     * @return  a ptr to an array of bitmaps or NULL if external storage is being used.
116     */
117    SkTRefArray<SkBitmap>* extractBitmaps() const;
118
119    /**
120     * Retrieves the bitmap from the specified slot in the heap
121     *
122     * @return  The bitmap located at that slot or NULL if external storage is being used.
123     */
124    virtual SkBitmap* getBitmap(int32_t slot) const SK_OVERRIDE {
125        SkASSERT(fExternalStorage == NULL);
126        SkBitmapHeapEntry* entry = getEntry(slot);
127        if (entry) {
128            return &entry->fBitmap;
129        }
130        return NULL;
131    }
132
133    /**
134     * Retrieves the bitmap from the specified slot in the heap
135     *
136     * @return  The bitmap located at that slot or NULL if external storage is being used.
137     */
138    virtual void releaseRef(int32_t slot) SK_OVERRIDE {
139        SkASSERT(fExternalStorage == NULL);
140        if (fOwnerCount != IGNORE_OWNERS) {
141            SkBitmapHeapEntry* entry = getEntry(slot);
142            if (entry) {
143                entry->releaseRef();
144            }
145        }
146    }
147
148    /**
149     * Inserts a bitmap into the heap. The stored version of bitmap is guaranteed to be immutable
150     * and is not dependent on the lifecycle of the provided bitmap.
151     *
152     * @param bitmap  the bitmap to be inserted into the heap
153     * @return  the slot in the heap where the bitmap is stored or INVALID_SLOT if the bitmap could
154     *          not be added to the heap. If it was added the slot will remain valid...
155     *            (1) indefinitely if no owner count has been specified.
156     *            (2) until all owners have called releaseRef on the appropriate SkBitmapHeapEntry*
157     */
158    int32_t insert(const SkBitmap& bitmap);
159
160    /**
161     * Retrieves an entry from the heap at a given slot.
162     *
163     * @param slot  the slot in the heap where a bitmap was stored.
164     * @return  a SkBitmapHeapEntry that wraps the bitmap or NULL if external storage is used.
165     */
166    SkBitmapHeapEntry* getEntry(int32_t slot) const {
167        SkASSERT(slot <= fStorage.count());
168        if (fExternalStorage != NULL) {
169            return NULL;
170        }
171        return fStorage[slot];
172    }
173
174    /**
175     * Returns a count of the number of items currently in the heap
176     */
177    int count() const {
178        SkASSERT(fExternalStorage != NULL || fStorage.count() == fLookupTable.count());
179        return fLookupTable.count();
180    }
181
182    /**
183     * Returns the total number of bytes allocated by the bitmaps in the heap
184     */
185    size_t bytesAllocated() const {
186        return fBytesAllocated;
187    }
188
189private:
190    struct LookupEntry {
191        uint32_t fGenerationId; // SkPixelRef GenerationID.
192        size_t fPixelOffset;
193        uint32_t fWidth;
194        uint32_t fHeight;
195
196        uint32_t fStorageSlot; // slot of corresponding bitmap in fStorage.
197
198        bool operator < (const LookupEntry& other) const {
199            if (this->fGenerationId != other.fGenerationId) {
200                return this->fGenerationId < other.fGenerationId;
201            } else if(this->fPixelOffset != other.fPixelOffset) {
202                return this->fPixelOffset < other.fPixelOffset;
203            } else if(this->fWidth != other.fWidth) {
204                return this->fWidth < other.fWidth;
205            } else {
206                return this->fHeight < other.fHeight;
207            }
208        }
209        bool operator != (const LookupEntry& other) const {
210            return this->fGenerationId != other.fGenerationId
211                || this->fPixelOffset != other.fPixelOffset
212                || this->fWidth != other.fWidth
213                || this->fHeight != other.fHeight;
214        }
215    };
216
217    /**
218     * Searches for the bitmap in the lookup table and returns the bitmaps index within the table.
219     * If the bitmap was not already in the table it is added.
220     *
221     * @param bitmap  The bitmap we using as a key to search the lookup table
222     * @param entry  A pointer to a SkBitmapHeapEntry* that if non-null AND the bitmap is found
223     *               in the lookup table is populated with the entry from the heap storage.
224     */
225    int findInLookupTable(const SkBitmap& bitmap, SkBitmapHeapEntry** entry);
226
227    SkBitmapHeapEntry* findEntryToReplace(const SkBitmap& replacement);
228    bool copyBitmap(const SkBitmap& originalBitmap, SkBitmap& copiedBitmap);
229    void setMostRecentlyUsed(SkBitmapHeapEntry* entry);
230
231    // searchable index that maps to entries in the heap
232    SkTDArray<LookupEntry> fLookupTable;
233
234    // heap storage
235    SkTDArray<SkBitmapHeapEntry*> fStorage;
236    ExternalStorage* fExternalStorage;
237
238    SkBitmapHeapEntry* fMostRecentlyUsed;
239    SkBitmapHeapEntry* fLeastRecentlyUsed;
240
241    const int32_t fPreferredCount;
242    const int32_t fOwnerCount;
243    size_t fBytesAllocated;
244
245    typedef SkBitmapHeapReader INHERITED;
246};
247
248#endif // SkBitmapHeap_DEFINED
249