235b11a394b7b6e9f778381b5764b9acdad883d7
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / gpu / GrResourceCache.h
1
2 /*
3  * Copyright 2011 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
9
10
11 #ifndef GrResourceCache_DEFINED
12 #define GrResourceCache_DEFINED
13
14 #include "GrConfig.h"
15 #include "GrTypes.h"
16 #include "SkTMultiMap.h"
17 #include "GrBinHashKey.h"
18 #include "SkMessageBus.h"
19 #include "SkTInternalLList.h"
20
21 class GrGpuResource;
22 class GrResourceCache;
23 class GrResourceCacheEntry;
24
25 class GrResourceKey {
26 public:
27     static GrCacheID::Domain ScratchDomain() {
28         static const GrCacheID::Domain gDomain = GrCacheID::GenerateDomain();
29         return gDomain;
30     }
31
32     /** Uniquely identifies the GrGpuResource subclass in the key to avoid collisions
33         across resource types. */
34     typedef uint8_t ResourceType;
35
36     /** Flags set by the GrGpuResource subclass. */
37     typedef uint8_t ResourceFlags;
38
39     /** Generate a unique ResourceType */
40     static ResourceType GenerateResourceType();
41
42     /** Creates a key for resource */
43     GrResourceKey(const GrCacheID& id, ResourceType type, ResourceFlags flags) {
44         this->init(id.getDomain(), id.getKey(), type, flags);
45     };
46
47     GrResourceKey(const GrResourceKey& src) {
48         fKey = src.fKey;
49     }
50
51     GrResourceKey() {
52         fKey.reset();
53     }
54
55     void reset(const GrCacheID& id, ResourceType type, ResourceFlags flags) {
56         this->init(id.getDomain(), id.getKey(), type, flags);
57     }
58
59     uint32_t getHash() const {
60         return fKey.getHash();
61     }
62
63     bool isScratch() const {
64         return ScratchDomain() ==
65             *reinterpret_cast<const GrCacheID::Domain*>(fKey.getData() +
66                                                         kCacheIDDomainOffset);
67     }
68
69     ResourceType getResourceType() const {
70         return *reinterpret_cast<const ResourceType*>(fKey.getData() +
71                                                       kResourceTypeOffset);
72     }
73
74     ResourceFlags getResourceFlags() const {
75         return *reinterpret_cast<const ResourceFlags*>(fKey.getData() +
76                                                        kResourceFlagsOffset);
77     }
78
79     bool operator==(const GrResourceKey& other) const { return fKey == other.fKey; }
80
81 private:
82     enum {
83         kCacheIDKeyOffset = 0,
84         kCacheIDDomainOffset = kCacheIDKeyOffset + sizeof(GrCacheID::Key),
85         kResourceTypeOffset = kCacheIDDomainOffset + sizeof(GrCacheID::Domain),
86         kResourceFlagsOffset = kResourceTypeOffset + sizeof(ResourceType),
87         kPadOffset = kResourceFlagsOffset + sizeof(ResourceFlags),
88         kKeySize = SkAlign4(kPadOffset),
89         kPadSize = kKeySize - kPadOffset
90     };
91
92     void init(const GrCacheID::Domain domain,
93               const GrCacheID::Key& key,
94               ResourceType type,
95               ResourceFlags flags) {
96         union {
97             uint8_t  fKey8[kKeySize];
98             uint32_t fKey32[kKeySize / 4];
99         } keyData;
100
101         uint8_t* k = keyData.fKey8;
102         memcpy(k + kCacheIDKeyOffset, key.fData8, sizeof(GrCacheID::Key));
103         memcpy(k + kCacheIDDomainOffset, &domain, sizeof(GrCacheID::Domain));
104         memcpy(k + kResourceTypeOffset, &type, sizeof(ResourceType));
105         memcpy(k + kResourceFlagsOffset, &flags, sizeof(ResourceFlags));
106         memset(k + kPadOffset, 0, kPadSize);
107         fKey.setKeyData(keyData.fKey32);
108     }
109     GrBinHashKey<kKeySize> fKey;
110 };
111
112 // The cache listens for these messages to purge junk resources proactively.
113 struct GrResourceInvalidatedMessage {
114     GrResourceKey key;
115 };
116
117 ///////////////////////////////////////////////////////////////////////////////
118
119 class GrResourceCacheEntry {
120 public:
121     GrGpuResource* resource() const { return fResource; }
122     const GrResourceKey& key() const { return fKey; }
123
124     static const GrResourceKey& GetKey(const GrResourceCacheEntry& e) { return e.key(); }
125     static uint32_t Hash(const GrResourceKey& key) { return key.getHash(); }
126 #ifdef SK_DEBUG
127     void validate() const;
128 #else
129     void validate() const {}
130 #endif
131
132     /**
133      *  Update the cached size for this entry and inform the resource cache that
134      *  it has changed. Usually invoked from GrGpuResource::didChangeGpuMemorySize,
135      *  not directly from here.
136      */
137     void didChangeResourceSize();
138
139 private:
140     GrResourceCacheEntry(GrResourceCache* resourceCache,
141                          const GrResourceKey& key,
142                          GrGpuResource* resource);
143     ~GrResourceCacheEntry();
144
145     GrResourceCache* fResourceCache;
146     GrResourceKey    fKey;
147     GrGpuResource*   fResource;
148     size_t           fCachedSize;
149     bool             fIsExclusive;
150
151     // Linked list for the LRU ordering.
152     SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrResourceCacheEntry);
153
154     friend class GrResourceCache;
155 };
156
157 ///////////////////////////////////////////////////////////////////////////////
158
159 /**
160  *  Cache of GrGpuResource objects.
161  *
162  *  These have a corresponding GrResourceKey, built from 128bits identifying the
163  *  resource. Multiple resources can map to same GrResourceKey.
164  *
165  *  The cache stores the entries in a double-linked list, which is its LRU.
166  *  When an entry is "locked" (i.e. given to the caller), it is moved to the
167  *  head of the list. If/when we must purge some of the entries, we walk the
168  *  list backwards from the tail, since those are the least recently used.
169  *
170  *  For fast searches, we maintain a hash map based on the GrResourceKey.
171  *
172  *  It is a goal to make the GrResourceCache the central repository and bookkeeper
173  *  of all resources. It should replace the linked list of GrGpuResources that
174  *  GrGpu uses to call abandon/release.
175  */
176 class GrResourceCache {
177 public:
178     GrResourceCache(int maxCount, size_t maxBytes);
179     ~GrResourceCache();
180
181     /**
182      *  Return the current resource cache limits.
183      *
184      *  @param maxResource If non-null, returns maximum number of resources
185      *                     that can be held in the cache.
186      *  @param maxBytes    If non-null, returns maximum number of bytes of
187      *                     gpu memory that can be held in the cache.
188      */
189     void getLimits(int* maxResources, size_t* maxBytes) const;
190
191     /**
192      *  Specify the resource cache limits. If the current cache exceeds either
193      *  of these, it will be purged (LRU) to keep the cache within these limits.
194      *
195      *  @param maxResources The maximum number of resources that can be held in
196      *                      the cache.
197      *  @param maxBytes     The maximum number of bytes of resource memory that
198      *                      can be held in the cache.
199      */
200     void setLimits(int maxResources, size_t maxResourceBytes);
201
202     /**
203      *  The callback function used by the cache when it is still over budget
204      *  after a purge. The passed in 'data' is the same 'data' handed to
205      *  setOverbudgetCallback. The callback returns true if some resources
206      *  have been freed.
207      */
208     typedef bool (*PFOverbudgetCB)(void* data);
209
210     /**
211      *  Set the callback the cache should use when it is still over budget
212      *  after a purge. The 'data' provided here will be passed back to the
213      *  callback. Note that the cache will attempt to purge any resources newly
214      *  freed by the callback.
215      */
216     void setOverbudgetCallback(PFOverbudgetCB overbudgetCB, void* data) {
217         fOverbudgetCB = overbudgetCB;
218         fOverbudgetData = data;
219     }
220
221     /**
222      * Returns the number of bytes consumed by cached resources.
223      */
224     size_t getCachedResourceBytes() const { return fEntryBytes; }
225
226     /**
227      * Returns the number of cached resources.
228      */
229     int getCachedResourceCount() const { return fEntryCount; }
230
231     // For a found or added resource to be completely exclusive to the caller
232     // both the kNoOtherOwners and kHide flags need to be specified
233     enum OwnershipFlags {
234         kNoOtherOwners_OwnershipFlag = 0x1, // found/added resource has no other owners
235         kHide_OwnershipFlag = 0x2  // found/added resource is hidden from future 'find's
236     };
237
238     /**
239      *  Search for an entry with the same Key. If found, return it.
240      *  If not found, return null.
241      *  If ownershipFlags includes kNoOtherOwners and a resource is returned
242      *  then that resource has no other refs to it.
243      *  If ownershipFlags includes kHide and a resource is returned then that
244      *  resource will not be returned from future 'find' calls until it is
245      *  'freed' (and recycled) or makeNonExclusive is called.
246      *  For a resource to be completely exclusive to a caller both kNoOtherOwners
247      *  and kHide must be specified.
248      */
249     GrGpuResource* find(const GrResourceKey& key,
250                         uint32_t ownershipFlags = 0);
251
252     /**
253      *  Add the new resource to the cache (by creating a new cache entry based
254      *  on the provided key and resource).
255      *
256      *  Ownership of the resource is transferred to the resource cache,
257      *  which will unref() it when it is purged or deleted.
258      *
259      *  If ownershipFlags includes kHide, subsequent calls to 'find' will not
260      *  return 'resource' until it is 'freed' (and recycled) or makeNonExclusive
261      *  is called.
262      */
263     void addResource(const GrResourceKey& key,
264                      GrGpuResource* resource,
265                      uint32_t ownershipFlags = 0);
266
267     /**
268      * Determines if the cache contains an entry matching a key. If a matching
269      * entry exists but was detached then it will not be found.
270      */
271     bool hasKey(const GrResourceKey& key) const { return NULL != fCache.find(key); }
272
273     /**
274      * Hide 'entry' so that future searches will not find it. Such
275      * hidden entries will not be purged. The entry still counts against
276      * the cache's budget and should be made non-exclusive when exclusive access
277      * is no longer needed.
278      */
279     void makeExclusive(GrResourceCacheEntry* entry);
280
281     /**
282      * Restore 'entry' so that it can be found by future searches. 'entry'
283      * will also be purgeable (provided its lock count is now 0.)
284      */
285     void makeNonExclusive(GrResourceCacheEntry* entry);
286
287     /**
288      * Notify the cache that the size of a resource has changed.
289      */
290     void didIncreaseResourceSize(const GrResourceCacheEntry*, size_t amountInc);
291     void didDecreaseResourceSize(const GrResourceCacheEntry*, size_t amountDec);
292
293     /**
294      * Remove a resource from the cache and delete it!
295      */
296     void deleteResource(GrResourceCacheEntry* entry);
297
298     /**
299      * Removes every resource in the cache that isn't locked.
300      */
301     void purgeAllUnlocked();
302
303     /**
304      * Allow cache to purge unused resources to obey resource limitations
305      * Note: this entry point will be hidden (again) once totally ref-driven
306      * cache maintenance is implemented. Note that the overbudget callback
307      * will be called if the initial purge doesn't get the cache under
308      * its budget.
309      *
310      * extraCount and extraBytes are added to the current resource allocation
311      * to make sure enough room is available for future additions (e.g,
312      * 10MB across 10 textures is about to be added).
313      */
314     void purgeAsNeeded(int extraCount = 0, size_t extraBytes = 0);
315
316 #ifdef SK_DEBUG
317     void validate() const;
318 #else
319     void validate() const {}
320 #endif
321
322 #if GR_CACHE_STATS
323     void printStats();
324 #endif
325
326 private:
327     enum BudgetBehaviors {
328         kAccountFor_BudgetBehavior,
329         kIgnore_BudgetBehavior
330     };
331
332     void internalDetach(GrResourceCacheEntry*, BudgetBehaviors behavior = kAccountFor_BudgetBehavior);
333     void attachToHead(GrResourceCacheEntry*, BudgetBehaviors behavior = kAccountFor_BudgetBehavior);
334
335     void removeInvalidResource(GrResourceCacheEntry* entry);
336
337     SkTMultiMap<GrResourceCacheEntry, GrResourceKey> fCache;
338
339     // We're an internal doubly linked list
340     typedef SkTInternalLList<GrResourceCacheEntry> EntryList;
341     EntryList      fList;
342
343 #ifdef SK_DEBUG
344     // These objects cannot be returned by a search
345     EntryList      fExclusiveList;
346 #endif
347
348     // our budget, used in purgeAsNeeded()
349     int            fMaxCount;
350     size_t         fMaxBytes;
351
352     // our current stats, related to our budget
353 #if GR_CACHE_STATS
354     int            fHighWaterEntryCount;
355     size_t         fHighWaterEntryBytes;
356     int            fHighWaterClientDetachedCount;
357     size_t         fHighWaterClientDetachedBytes;
358 #endif
359
360     int            fEntryCount;
361     size_t         fEntryBytes;
362     int            fClientDetachedCount;
363     size_t         fClientDetachedBytes;
364
365     // prevents recursive purging
366     bool           fPurging;
367
368     PFOverbudgetCB fOverbudgetCB;
369     void*          fOverbudgetData;
370
371     void internalPurge(int extraCount, size_t extraBytes);
372
373     // Listen for messages that a resource has been invalidated and purge cached junk proactively.
374     SkMessageBus<GrResourceInvalidatedMessage>::Inbox fInvalidationInbox;
375     void purgeInvalidated();
376
377 #ifdef SK_DEBUG
378     static size_t countBytes(const SkTInternalLList<GrResourceCacheEntry>& list);
379 #endif
380 };
381
382 ///////////////////////////////////////////////////////////////////////////////
383
384 #ifdef SK_DEBUG
385     class GrAutoResourceCacheValidate {
386     public:
387         GrAutoResourceCacheValidate(GrResourceCache* cache) : fCache(cache) {
388             cache->validate();
389         }
390         ~GrAutoResourceCacheValidate() {
391             fCache->validate();
392         }
393     private:
394         GrResourceCache* fCache;
395     };
396 #else
397     class GrAutoResourceCacheValidate {
398     public:
399         GrAutoResourceCacheValidate(GrResourceCache*) {}
400     };
401 #endif
402
403 #endif