Home | History | Annotate | Download | only in gpu
      1 /*
      2  * Copyright 2014 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 GrResourceCache_DEFINED
      9 #define GrResourceCache_DEFINED
     10 
     11 #include "GrGpuResource.h"
     12 #include "GrGpuResourceCacheAccess.h"
     13 #include "GrGpuResourcePriv.h"
     14 #include "GrResourceKey.h"
     15 #include "SkMessageBus.h"
     16 #include "SkRefCnt.h"
     17 #include "SkTArray.h"
     18 #include "SkTDPQueue.h"
     19 #include "SkTInternalLList.h"
     20 #include "SkTMultiMap.h"
     21 
     22 class GrCaps;
     23 class GrProxyProvider;
     24 class SkString;
     25 class SkTraceMemoryDump;
     26 class GrSingleOwner;
     27 
     28 struct GrGpuResourceFreedMessage {
     29     GrGpuResource* fResource;
     30     uint32_t fOwningUniqueID;
     31 };
     32 
     33 static inline bool SkShouldPostMessageToBus(
     34         const GrGpuResourceFreedMessage& msg, uint32_t msgBusUniqueID) {
     35     // The inbox's ID is the unique ID of the owning GrContext.
     36     return msgBusUniqueID == msg.fOwningUniqueID;
     37 }
     38 
     39 /**
     40  * Manages the lifetime of all GrGpuResource instances.
     41  *
     42  * Resources may have optionally have two types of keys:
     43  *      1) A scratch key. This is for resources whose allocations are cached but not their contents.
     44  *         Multiple resources can share the same scratch key. This is so a caller can have two
     45  *         resource instances with the same properties (e.g. multipass rendering that ping-pongs
     46  *         between two temporary surfaces). The scratch key is set at resource creation time and
     47  *         should never change. Resources need not have a scratch key.
     48  *      2) A unique key. This key's meaning is specific to the domain that created the key. Only one
     49  *         resource may have a given unique key. The unique key can be set, cleared, or changed
     50  *         anytime after resource creation.
     51  *
     52  * A unique key always takes precedence over a scratch key when a resource has both types of keys.
     53  * If a resource has neither key type then it will be deleted as soon as the last reference to it
     54  * is dropped.
     55  */
     56 class GrResourceCache {
     57 public:
     58     GrResourceCache(const GrCaps*, GrSingleOwner* owner, uint32_t contextUniqueID);
     59     ~GrResourceCache();
     60 
     61     // Default maximum number of budgeted resources in the cache.
     62     static const int    kDefaultMaxCount            = 2 * (1 << 12);
     63     // Default maximum number of bytes of gpu memory of budgeted resources in the cache.
     64     static const size_t kDefaultMaxSize             = 96 * (1 << 20);
     65 
     66     /** Used to access functionality needed by GrGpuResource for lifetime management. */
     67     class ResourceAccess;
     68     ResourceAccess resourceAccess();
     69 
     70     /** Unique ID of the owning GrContext. */
     71     uint32_t contextUniqueID() const { return fContextUniqueID; }
     72 
     73     /** Sets the cache limits in terms of number of resources and max gpu memory byte size. */
     74     void setLimits(int count, size_t bytes);
     75 
     76     /**
     77      * Returns the number of resources.
     78      */
     79     int getResourceCount() const {
     80         return fPurgeableQueue.count() + fNonpurgeableResources.count();
     81     }
     82 
     83     /**
     84      * Returns the number of resources that count against the budget.
     85      */
     86     int getBudgetedResourceCount() const { return fBudgetedCount; }
     87 
     88     /**
     89      * Returns the number of bytes consumed by resources.
     90      */
     91     size_t getResourceBytes() const { return fBytes; }
     92 
     93     /**
     94      * Returns the number of bytes held by unlocked reosources which are available for purging.
     95      */
     96     size_t getPurgeableBytes() const { return fPurgeableBytes; }
     97 
     98     /**
     99      * Returns the number of bytes consumed by budgeted resources.
    100      */
    101     size_t getBudgetedResourceBytes() const { return fBudgetedBytes; }
    102 
    103     /**
    104      * Returns the cached resources count budget.
    105      */
    106     int getMaxResourceCount() const { return fMaxCount; }
    107 
    108     /**
    109      * Returns the number of bytes consumed by cached resources.
    110      */
    111     size_t getMaxResourceBytes() const { return fMaxBytes; }
    112 
    113     /**
    114      * Abandons the backend API resources owned by all GrGpuResource objects and removes them from
    115      * the cache.
    116      */
    117     void abandonAll();
    118 
    119     /**
    120      * Releases the backend API resources owned by all GrGpuResource objects and removes them from
    121      * the cache.
    122      */
    123     void releaseAll();
    124 
    125     enum class ScratchFlags {
    126         kNone = 0,
    127         /** Preferentially returns scratch resources with no pending IO. */
    128         kPreferNoPendingIO = 0x1,
    129         /** Will not return any resources that match but have pending IO. */
    130         kRequireNoPendingIO = 0x2,
    131     };
    132 
    133     /**
    134      * Find a resource that matches a scratch key.
    135      */
    136     GrGpuResource* findAndRefScratchResource(const GrScratchKey& scratchKey, size_t resourceSize,
    137                                              ScratchFlags);
    138 
    139 #ifdef SK_DEBUG
    140     // This is not particularly fast and only used for validation, so debug only.
    141     int countScratchEntriesForKey(const GrScratchKey& scratchKey) const {
    142         return fScratchMap.countForKey(scratchKey);
    143     }
    144 #endif
    145 
    146     /**
    147      * Find a resource that matches a unique key.
    148      */
    149     GrGpuResource* findAndRefUniqueResource(const GrUniqueKey& key) {
    150         GrGpuResource* resource = fUniqueHash.find(key);
    151         if (resource) {
    152             this->refAndMakeResourceMRU(resource);
    153         }
    154         return resource;
    155     }
    156 
    157     /**
    158      * Query whether a unique key exists in the cache.
    159      */
    160     bool hasUniqueKey(const GrUniqueKey& key) const {
    161         return SkToBool(fUniqueHash.find(key));
    162     }
    163 
    164     /** Purges resources to become under budget and processes resources with invalidated unique
    165         keys. */
    166     void purgeAsNeeded();
    167 
    168     /** Purges all resources that don't have external owners. */
    169     void purgeAllUnlocked() { this->purgeUnlockedResources(false); }
    170 
    171     // Purge unlocked resources. If 'scratchResourcesOnly' is true the purgeable resources
    172     // containing persistent data are spared. If it is false then all purgeable resources will
    173     // be deleted.
    174     void purgeUnlockedResources(bool scratchResourcesOnly);
    175 
    176     /** Purge all resources not used since the passed in time. */
    177     void purgeResourcesNotUsedSince(GrStdSteadyClock::time_point);
    178 
    179     bool overBudget() const { return fBudgetedBytes > fMaxBytes || fBudgetedCount > fMaxCount; }
    180 
    181     /**
    182      * Purge unlocked resources from the cache until the the provided byte count has been reached
    183      * or we have purged all unlocked resources. The default policy is to purge in LRU order, but
    184      * can be overridden to prefer purging scratch resources (in LRU order) prior to purging other
    185      * resource types.
    186      *
    187      * @param maxBytesToPurge the desired number of bytes to be purged.
    188      * @param preferScratchResources If true scratch resources will be purged prior to other
    189      *                               resource types.
    190      */
    191     void purgeUnlockedResources(size_t bytesToPurge, bool preferScratchResources);
    192 
    193     /** Returns true if the cache would like a flush to occur in order to make more resources
    194         purgeable. */
    195     bool requestsFlush() const { return this->overBudget() && !fPurgeableQueue.count(); }
    196 
    197     /** Maintain a ref to this resource until we receive a GrGpuResourceFreedMessage. */
    198     void insertCrossContextGpuResource(GrGpuResource* resource);
    199 
    200 #if GR_CACHE_STATS
    201     struct Stats {
    202         int fTotal;
    203         int fNumPurgeable;
    204         int fNumNonPurgeable;
    205 
    206         int fScratch;
    207         int fWrapped;
    208         size_t fUnbudgetedSize;
    209 
    210         Stats() { this->reset(); }
    211 
    212         void reset() {
    213             fTotal = 0;
    214             fNumPurgeable = 0;
    215             fNumNonPurgeable = 0;
    216             fScratch = 0;
    217             fWrapped = 0;
    218             fUnbudgetedSize = 0;
    219         }
    220 
    221         void update(GrGpuResource* resource) {
    222             if (resource->cacheAccess().isScratch()) {
    223                 ++fScratch;
    224             }
    225             if (resource->resourcePriv().refsWrappedObjects()) {
    226                 ++fWrapped;
    227             }
    228             if (GrBudgetedType::kBudgeted != resource->resourcePriv().budgetedType()) {
    229                 fUnbudgetedSize += resource->gpuMemorySize();
    230             }
    231         }
    232     };
    233 
    234     void getStats(Stats*) const;
    235 
    236     void dumpStats(SkString*) const;
    237 
    238     void dumpStatsKeyValuePairs(SkTArray<SkString>* keys, SkTArray<double>* value) const;
    239 #endif
    240 
    241 #ifdef SK_DEBUG
    242     int countUniqueKeysWithTag(const char* tag) const;
    243 #endif
    244 
    245     // This function is for unit testing and is only defined in test tools.
    246     void changeTimestamp(uint32_t newTimestamp);
    247 
    248     // Enumerates all cached resources and dumps their details to traceMemoryDump.
    249     void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const;
    250 
    251     void setProxyProvider(GrProxyProvider* proxyProvider) { fProxyProvider = proxyProvider; }
    252 
    253 private:
    254     ///////////////////////////////////////////////////////////////////////////
    255     /// @name Methods accessible via ResourceAccess
    256     ////
    257     void insertResource(GrGpuResource*);
    258     void removeResource(GrGpuResource*);
    259     void notifyCntReachedZero(GrGpuResource*, uint32_t flags);
    260     void changeUniqueKey(GrGpuResource*, const GrUniqueKey&);
    261     void removeUniqueKey(GrGpuResource*);
    262     void willRemoveScratchKey(const GrGpuResource*);
    263     void didChangeBudgetStatus(GrGpuResource*);
    264     void refAndMakeResourceMRU(GrGpuResource*);
    265     /// @}
    266 
    267     void processFreedGpuResources();
    268     void addToNonpurgeableArray(GrGpuResource*);
    269     void removeFromNonpurgeableArray(GrGpuResource*);
    270 
    271     bool wouldFit(size_t bytes) {
    272         return fBudgetedBytes+bytes <= fMaxBytes && fBudgetedCount+1 <= fMaxCount;
    273     }
    274 
    275     uint32_t getNextTimestamp();
    276 
    277 #ifdef SK_DEBUG
    278     bool isInCache(const GrGpuResource* r) const;
    279     void validate() const;
    280 #else
    281     void validate() const {}
    282 #endif
    283 
    284     class AutoValidate;
    285 
    286     class AvailableForScratchUse;
    287 
    288     struct ScratchMapTraits {
    289         static const GrScratchKey& GetKey(const GrGpuResource& r) {
    290             return r.resourcePriv().getScratchKey();
    291         }
    292 
    293         static uint32_t Hash(const GrScratchKey& key) { return key.hash(); }
    294         static void OnFree(GrGpuResource*) { }
    295     };
    296     typedef SkTMultiMap<GrGpuResource, GrScratchKey, ScratchMapTraits> ScratchMap;
    297 
    298     struct UniqueHashTraits {
    299         static const GrUniqueKey& GetKey(const GrGpuResource& r) { return r.getUniqueKey(); }
    300 
    301         static uint32_t Hash(const GrUniqueKey& key) { return key.hash(); }
    302     };
    303     typedef SkTDynamicHash<GrGpuResource, GrUniqueKey, UniqueHashTraits> UniqueHash;
    304 
    305     static bool CompareTimestamp(GrGpuResource* const& a, GrGpuResource* const& b) {
    306         return a->cacheAccess().timestamp() < b->cacheAccess().timestamp();
    307     }
    308 
    309     static int* AccessResourceIndex(GrGpuResource* const& res) {
    310         return res->cacheAccess().accessCacheIndex();
    311     }
    312 
    313     typedef SkMessageBus<GrUniqueKeyInvalidatedMessage>::Inbox InvalidUniqueKeyInbox;
    314     typedef SkMessageBus<GrGpuResourceFreedMessage>::Inbox FreedGpuResourceInbox;
    315     typedef SkTDPQueue<GrGpuResource*, CompareTimestamp, AccessResourceIndex> PurgeableQueue;
    316     typedef SkTDArray<GrGpuResource*> ResourceArray;
    317 
    318     GrProxyProvider*                    fProxyProvider;
    319     // Whenever a resource is added to the cache or the result of a cache lookup, fTimestamp is
    320     // assigned as the resource's timestamp and then incremented. fPurgeableQueue orders the
    321     // purgeable resources by this value, and thus is used to purge resources in LRU order.
    322     uint32_t                            fTimestamp;
    323     PurgeableQueue                      fPurgeableQueue;
    324     ResourceArray                       fNonpurgeableResources;
    325 
    326     // This map holds all resources that can be used as scratch resources.
    327     ScratchMap                          fScratchMap;
    328     // This holds all resources that have unique keys.
    329     UniqueHash                          fUniqueHash;
    330 
    331     // our budget, used in purgeAsNeeded()
    332     int                                 fMaxCount;
    333     size_t                              fMaxBytes;
    334 
    335 #if GR_CACHE_STATS
    336     int                                 fHighWaterCount;
    337     size_t                              fHighWaterBytes;
    338     int                                 fBudgetedHighWaterCount;
    339     size_t                              fBudgetedHighWaterBytes;
    340 #endif
    341 
    342     // our current stats for all resources
    343     SkDEBUGCODE(int                     fCount;)
    344     size_t                              fBytes;
    345 
    346     // our current stats for resources that count against the budget
    347     int                                 fBudgetedCount;
    348     size_t                              fBudgetedBytes;
    349     size_t                              fPurgeableBytes;
    350 
    351     InvalidUniqueKeyInbox               fInvalidUniqueKeyInbox;
    352     FreedGpuResourceInbox               fFreedGpuResourceInbox;
    353 
    354     SkTDArray<GrGpuResource*>           fResourcesWaitingForFreeMsg;
    355 
    356     uint32_t                            fContextUniqueID;
    357     GrSingleOwner*                      fSingleOwner;
    358 
    359     // This resource is allowed to be in the nonpurgeable array for the sake of validate() because
    360     // we're in the midst of converting it to purgeable status.
    361     SkDEBUGCODE(GrGpuResource*          fNewlyPurgeableResourceForValidation;)
    362 
    363     bool                                fPreferVRAMUseOverFlushes;
    364 };
    365 
    366 GR_MAKE_BITFIELD_CLASS_OPS(GrResourceCache::ScratchFlags);
    367 
    368 class GrResourceCache::ResourceAccess {
    369 private:
    370     ResourceAccess(GrResourceCache* cache) : fCache(cache) { }
    371     ResourceAccess(const ResourceAccess& that) : fCache(that.fCache) { }
    372     ResourceAccess& operator=(const ResourceAccess&); // unimpl
    373 
    374     /**
    375      * Insert a resource into the cache.
    376      */
    377     void insertResource(GrGpuResource* resource) { fCache->insertResource(resource); }
    378 
    379     /**
    380      * Removes a resource from the cache.
    381      */
    382     void removeResource(GrGpuResource* resource) { fCache->removeResource(resource); }
    383 
    384     /**
    385      * Notifications that should be sent to the cache when the ref/io cnt status of resources
    386      * changes.
    387      */
    388     enum RefNotificationFlags {
    389         /** All types of refs on the resource have reached zero. */
    390         kAllCntsReachedZero_RefNotificationFlag = 0x1,
    391         /** The normal (not pending IO type) ref cnt has reached zero. */
    392         kRefCntReachedZero_RefNotificationFlag  = 0x2,
    393     };
    394     /**
    395      * Called by GrGpuResources when they detect that their ref/io cnts have reached zero. When the
    396      * normal ref cnt reaches zero the flags that are set should be:
    397      *     a) kRefCntReachedZero if a pending IO cnt is still non-zero.
    398      *     b) (kRefCntReachedZero | kAllCntsReachedZero) when all pending IO cnts are also zero.
    399      * kAllCntsReachedZero is set by itself if a pending IO cnt is decremented to zero and all the
    400      * the other cnts are already zero.
    401      */
    402     void notifyCntReachedZero(GrGpuResource* resource, uint32_t flags) {
    403         fCache->notifyCntReachedZero(resource, flags);
    404     }
    405 
    406     /**
    407      * Called by GrGpuResources to change their unique keys.
    408      */
    409     void changeUniqueKey(GrGpuResource* resource, const GrUniqueKey& newKey) {
    410          fCache->changeUniqueKey(resource, newKey);
    411     }
    412 
    413     /**
    414      * Called by a GrGpuResource to remove its unique key.
    415      */
    416     void removeUniqueKey(GrGpuResource* resource) { fCache->removeUniqueKey(resource); }
    417 
    418     /**
    419      * Called by a GrGpuResource when it removes its scratch key.
    420      */
    421     void willRemoveScratchKey(const GrGpuResource* resource) {
    422         fCache->willRemoveScratchKey(resource);
    423     }
    424 
    425     /**
    426      * Called by GrGpuResources when they change from budgeted to unbudgeted or vice versa.
    427      */
    428     void didChangeBudgetStatus(GrGpuResource* resource) { fCache->didChangeBudgetStatus(resource); }
    429 
    430     // No taking addresses of this type.
    431     const ResourceAccess* operator&() const;
    432     ResourceAccess* operator&();
    433 
    434     GrResourceCache* fCache;
    435 
    436     friend class GrGpuResource; // To access all the proxy inline methods.
    437     friend class GrResourceCache; // To create this type.
    438 };
    439 
    440 inline GrResourceCache::ResourceAccess GrResourceCache::resourceAccess() {
    441     return ResourceAccess(this);
    442 }
    443 
    444 #endif
    445