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