Home | History | Annotate | Download | only in gpu
      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 "GrResourceKey.h"
     15 #include "SkTMultiMap.h"
     16 #include "SkMessageBus.h"
     17 #include "SkTInternalLList.h"
     18 
     19 class GrGpuResource;
     20 class GrResourceCache;
     21 class GrResourceCacheEntry;
     22 
     23 
     24 // The cache listens for these messages to purge junk resources proactively.
     25 struct GrResourceInvalidatedMessage {
     26     GrResourceKey key;
     27 };
     28 
     29 ///////////////////////////////////////////////////////////////////////////////
     30 
     31 class GrResourceCacheEntry {
     32 public:
     33     GrGpuResource* resource() const { return fResource; }
     34     const GrResourceKey& key() const { return fKey; }
     35 
     36     static const GrResourceKey& GetKey(const GrResourceCacheEntry& e) { return e.key(); }
     37     static uint32_t Hash(const GrResourceKey& key) { return key.getHash(); }
     38 #ifdef SK_DEBUG
     39     void validate() const;
     40 #else
     41     void validate() const {}
     42 #endif
     43 
     44     /**
     45      *  Update the cached size for this entry and inform the resource cache that
     46      *  it has changed. Usually invoked from GrGpuResource::didChangeGpuMemorySize,
     47      *  not directly from here.
     48      */
     49     void didChangeResourceSize();
     50 
     51 private:
     52     GrResourceCacheEntry(GrResourceCache* resourceCache,
     53                          const GrResourceKey& key,
     54                          GrGpuResource* resource);
     55     ~GrResourceCacheEntry();
     56 
     57     GrResourceCache* fResourceCache;
     58     GrResourceKey    fKey;
     59     GrGpuResource*   fResource;
     60     size_t           fCachedSize;
     61     bool             fIsExclusive;
     62 
     63     // Linked list for the LRU ordering.
     64     SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrResourceCacheEntry);
     65 
     66     friend class GrResourceCache;
     67     friend class GrContext;
     68 };
     69 
     70 ///////////////////////////////////////////////////////////////////////////////
     71 
     72 /**
     73  *  Cache of GrGpuResource objects.
     74  *
     75  *  These have a corresponding GrResourceKey, built from 128bits identifying the
     76  *  resource. Multiple resources can map to same GrResourceKey.
     77  *
     78  *  The cache stores the entries in a double-linked list, which is its LRU.
     79  *  When an entry is "locked" (i.e. given to the caller), it is moved to the
     80  *  head of the list. If/when we must purge some of the entries, we walk the
     81  *  list backwards from the tail, since those are the least recently used.
     82  *
     83  *  For fast searches, we maintain a hash map based on the GrResourceKey.
     84  *
     85  *  It is a goal to make the GrResourceCache the central repository and bookkeeper
     86  *  of all resources. It should replace the linked list of GrGpuResources that
     87  *  GrGpu uses to call abandon/release.
     88  */
     89 class GrResourceCache {
     90 public:
     91     GrResourceCache(int maxCount, size_t maxBytes);
     92     ~GrResourceCache();
     93 
     94     /**
     95      *  Return the current resource cache limits.
     96      *
     97      *  @param maxResource If non-null, returns maximum number of resources
     98      *                     that can be held in the cache.
     99      *  @param maxBytes    If non-null, returns maximum number of bytes of
    100      *                     gpu memory that can be held in the cache.
    101      */
    102     void getLimits(int* maxResources, size_t* maxBytes) const;
    103 
    104     /**
    105      *  Specify the resource cache limits. If the current cache exceeds either
    106      *  of these, it will be purged (LRU) to keep the cache within these limits.
    107      *
    108      *  @param maxResources The maximum number of resources that can be held in
    109      *                      the cache.
    110      *  @param maxBytes     The maximum number of bytes of resource memory that
    111      *                      can be held in the cache.
    112      */
    113     void setLimits(int maxResources, size_t maxResourceBytes);
    114 
    115     /**
    116      *  The callback function used by the cache when it is still over budget
    117      *  after a purge. The passed in 'data' is the same 'data' handed to
    118      *  setOverbudgetCallback. The callback returns true if some resources
    119      *  have been freed.
    120      */
    121     typedef bool (*PFOverbudgetCB)(void* data);
    122 
    123     /**
    124      *  Set the callback the cache should use when it is still over budget
    125      *  after a purge. The 'data' provided here will be passed back to the
    126      *  callback. Note that the cache will attempt to purge any resources newly
    127      *  freed by the callback.
    128      */
    129     void setOverbudgetCallback(PFOverbudgetCB overbudgetCB, void* data) {
    130         fOverbudgetCB = overbudgetCB;
    131         fOverbudgetData = data;
    132     }
    133 
    134     /**
    135      * Returns the number of bytes consumed by cached resources.
    136      */
    137     size_t getCachedResourceBytes() const { return fEntryBytes; }
    138 
    139     /**
    140      * Returns the number of cached resources.
    141      */
    142     int getCachedResourceCount() const { return fEntryCount; }
    143 
    144     // For a found or added resource to be completely exclusive to the caller
    145     // both the kNoOtherOwners and kHide flags need to be specified
    146     enum OwnershipFlags {
    147         kNoOtherOwners_OwnershipFlag = 0x1, // found/added resource has no other owners
    148         kHide_OwnershipFlag = 0x2  // found/added resource is hidden from future 'find's
    149     };
    150 
    151     /**
    152      *  Search for an entry with the same Key. If found, return it.
    153      *  If not found, return null.
    154      *  If ownershipFlags includes kNoOtherOwners and a resource is returned
    155      *  then that resource has no other refs to it.
    156      *  If ownershipFlags includes kHide and a resource is returned then that
    157      *  resource will not be returned from future 'find' calls until it is
    158      *  'freed' (and recycled) or makeNonExclusive is called.
    159      *  For a resource to be completely exclusive to a caller both kNoOtherOwners
    160      *  and kHide must be specified.
    161      */
    162     GrGpuResource* find(const GrResourceKey& key,
    163                         uint32_t ownershipFlags = 0);
    164 
    165     /**
    166      *  Add the new resource to the cache (by creating a new cache entry based
    167      *  on the provided key and resource).
    168      *
    169      *  Ownership of the resource is transferred to the resource cache,
    170      *  which will unref() it when it is purged or deleted.
    171      *
    172      *  If ownershipFlags includes kHide, subsequent calls to 'find' will not
    173      *  return 'resource' until it is 'freed' (and recycled) or makeNonExclusive
    174      *  is called.
    175      */
    176     void addResource(const GrResourceKey& key,
    177                      GrGpuResource* resource,
    178                      uint32_t ownershipFlags = 0);
    179 
    180     /**
    181      * Determines if the cache contains an entry matching a key. If a matching
    182      * entry exists but was detached then it will not be found.
    183      */
    184     bool hasKey(const GrResourceKey& key) const { return SkToBool(fCache.find(key)); }
    185 
    186     /**
    187      * Hide 'entry' so that future searches will not find it. Such
    188      * hidden entries will not be purged. The entry still counts against
    189      * the cache's budget and should be made non-exclusive when exclusive access
    190      * is no longer needed.
    191      */
    192     void makeExclusive(GrResourceCacheEntry* entry);
    193 
    194     /**
    195      * Restore 'entry' so that it can be found by future searches. 'entry'
    196      * will also be purgeable (provided its lock count is now 0.)
    197      */
    198     void makeNonExclusive(GrResourceCacheEntry* entry);
    199 
    200     /**
    201      * Notify the cache that the size of a resource has changed.
    202      */
    203     void didIncreaseResourceSize(const GrResourceCacheEntry*, size_t amountInc);
    204     void didDecreaseResourceSize(const GrResourceCacheEntry*, size_t amountDec);
    205 
    206     /**
    207      * Remove a resource from the cache and delete it!
    208      */
    209     void deleteResource(GrResourceCacheEntry* entry);
    210 
    211     /**
    212      * Removes every resource in the cache that isn't locked.
    213      */
    214     void purgeAllUnlocked();
    215 
    216     /**
    217      * Allow cache to purge unused resources to obey resource limitations
    218      * Note: this entry point will be hidden (again) once totally ref-driven
    219      * cache maintenance is implemented. Note that the overbudget callback
    220      * will be called if the initial purge doesn't get the cache under
    221      * its budget.
    222      *
    223      * extraCount and extraBytes are added to the current resource allocation
    224      * to make sure enough room is available for future additions (e.g,
    225      * 10MB across 10 textures is about to be added).
    226      */
    227     void purgeAsNeeded(int extraCount = 0, size_t extraBytes = 0);
    228 
    229 #ifdef SK_DEBUG
    230     void validate() const;
    231 #else
    232     void validate() const {}
    233 #endif
    234 
    235 #if GR_CACHE_STATS
    236     void printStats();
    237 #endif
    238 
    239 private:
    240     enum BudgetBehaviors {
    241         kAccountFor_BudgetBehavior,
    242         kIgnore_BudgetBehavior
    243     };
    244 
    245     void internalDetach(GrResourceCacheEntry*, BudgetBehaviors behavior = kAccountFor_BudgetBehavior);
    246     void attachToHead(GrResourceCacheEntry*, BudgetBehaviors behavior = kAccountFor_BudgetBehavior);
    247 
    248     void removeInvalidResource(GrResourceCacheEntry* entry);
    249 
    250     SkTMultiMap<GrResourceCacheEntry, GrResourceKey> fCache;
    251 
    252     // We're an internal doubly linked list
    253     typedef SkTInternalLList<GrResourceCacheEntry> EntryList;
    254     EntryList      fList;
    255 
    256 #ifdef SK_DEBUG
    257     // These objects cannot be returned by a search
    258     EntryList      fExclusiveList;
    259 #endif
    260 
    261     // our budget, used in purgeAsNeeded()
    262     int            fMaxCount;
    263     size_t         fMaxBytes;
    264 
    265     // our current stats, related to our budget
    266 #if GR_CACHE_STATS
    267     int            fHighWaterEntryCount;
    268     size_t         fHighWaterEntryBytes;
    269     int            fHighWaterClientDetachedCount;
    270     size_t         fHighWaterClientDetachedBytes;
    271 #endif
    272 
    273     int            fEntryCount;
    274     size_t         fEntryBytes;
    275     int            fClientDetachedCount;
    276     size_t         fClientDetachedBytes;
    277 
    278     // prevents recursive purging
    279     bool           fPurging;
    280 
    281     PFOverbudgetCB fOverbudgetCB;
    282     void*          fOverbudgetData;
    283 
    284     void internalPurge(int extraCount, size_t extraBytes);
    285 
    286     // Listen for messages that a resource has been invalidated and purge cached junk proactively.
    287     SkMessageBus<GrResourceInvalidatedMessage>::Inbox fInvalidationInbox;
    288     void purgeInvalidated();
    289 
    290 #ifdef SK_DEBUG
    291     static size_t countBytes(const SkTInternalLList<GrResourceCacheEntry>& list);
    292 #endif
    293 };
    294 
    295 ///////////////////////////////////////////////////////////////////////////////
    296 
    297 #ifdef SK_DEBUG
    298     class GrAutoResourceCacheValidate {
    299     public:
    300         GrAutoResourceCacheValidate(GrResourceCache* cache) : fCache(cache) {
    301             cache->validate();
    302         }
    303         ~GrAutoResourceCacheValidate() {
    304             fCache->validate();
    305         }
    306     private:
    307         GrResourceCache* fCache;
    308     };
    309 #else
    310     class GrAutoResourceCacheValidate {
    311     public:
    312         GrAutoResourceCacheValidate(GrResourceCache*) {}
    313     };
    314 #endif
    315 
    316 #endif
    317