xref: /aosp_15_r20/external/skia/src/gpu/graphite/ResourceCache.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2022 Google LLC
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #ifndef skgpu_graphite_ResourceCache_DEFINED
9*c8dee2aaSAndroid Build Coastguard Worker #define skgpu_graphite_ResourceCache_DEFINED
10*c8dee2aaSAndroid Build Coastguard Worker 
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkMutex.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTArray.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkTDPQueue.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkTHash.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkTMultiMap.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/GpuTypesPriv.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/ResourceTypes.h"
19*c8dee2aaSAndroid Build Coastguard Worker 
20*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
21*c8dee2aaSAndroid Build Coastguard Worker #include <functional>
22*c8dee2aaSAndroid Build Coastguard Worker #endif
23*c8dee2aaSAndroid Build Coastguard Worker #include <vector>
24*c8dee2aaSAndroid Build Coastguard Worker 
25*c8dee2aaSAndroid Build Coastguard Worker class SkTraceMemoryDump;
26*c8dee2aaSAndroid Build Coastguard Worker 
27*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu {
28*c8dee2aaSAndroid Build Coastguard Worker class SingleOwner;
29*c8dee2aaSAndroid Build Coastguard Worker }
30*c8dee2aaSAndroid Build Coastguard Worker 
31*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::graphite {
32*c8dee2aaSAndroid Build Coastguard Worker 
33*c8dee2aaSAndroid Build Coastguard Worker class GraphiteResourceKey;
34*c8dee2aaSAndroid Build Coastguard Worker class ProxyCache;
35*c8dee2aaSAndroid Build Coastguard Worker class Resource;
36*c8dee2aaSAndroid Build Coastguard Worker 
37*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
38*c8dee2aaSAndroid Build Coastguard Worker class Texture;
39*c8dee2aaSAndroid Build Coastguard Worker #endif
40*c8dee2aaSAndroid Build Coastguard Worker 
41*c8dee2aaSAndroid Build Coastguard Worker class ResourceCache : public SkRefCnt {
42*c8dee2aaSAndroid Build Coastguard Worker public:
43*c8dee2aaSAndroid Build Coastguard Worker     static sk_sp<ResourceCache> Make(SingleOwner*, uint32_t recorderID, size_t maxBytes);
44*c8dee2aaSAndroid Build Coastguard Worker     ~ResourceCache() override;
45*c8dee2aaSAndroid Build Coastguard Worker 
46*c8dee2aaSAndroid Build Coastguard Worker     ResourceCache(const ResourceCache&) = delete;
47*c8dee2aaSAndroid Build Coastguard Worker     ResourceCache(ResourceCache&&) = delete;
48*c8dee2aaSAndroid Build Coastguard Worker     ResourceCache& operator=(const ResourceCache&) = delete;
49*c8dee2aaSAndroid Build Coastguard Worker     ResourceCache& operator=(ResourceCache&&) = delete;
50*c8dee2aaSAndroid Build Coastguard Worker 
51*c8dee2aaSAndroid Build Coastguard Worker     // Returns the number of resources.
getResourceCount()52*c8dee2aaSAndroid Build Coastguard Worker     int getResourceCount() const {
53*c8dee2aaSAndroid Build Coastguard Worker         return fPurgeableQueue.count() + fNonpurgeableResources.size();
54*c8dee2aaSAndroid Build Coastguard Worker     }
55*c8dee2aaSAndroid Build Coastguard Worker 
56*c8dee2aaSAndroid Build Coastguard Worker     void insertResource(Resource*);
57*c8dee2aaSAndroid Build Coastguard Worker 
58*c8dee2aaSAndroid Build Coastguard Worker     // Find a resource that matches a key.
59*c8dee2aaSAndroid Build Coastguard Worker     Resource* findAndRefResource(const GraphiteResourceKey& key, skgpu::Budgeted);
60*c8dee2aaSAndroid Build Coastguard Worker 
61*c8dee2aaSAndroid Build Coastguard Worker     // This is a thread safe call. If it fails the ResourceCache is no longer valid and the
62*c8dee2aaSAndroid Build Coastguard Worker     // Resource should clean itself up if it is the last ref.
63*c8dee2aaSAndroid Build Coastguard Worker     bool returnResource(Resource*, LastRemovedRef);
64*c8dee2aaSAndroid Build Coastguard Worker 
65*c8dee2aaSAndroid Build Coastguard Worker     // Purge resources not used since the passed point in time. Resources that have a gpu memory
66*c8dee2aaSAndroid Build Coastguard Worker     // size of zero will not be purged.
67*c8dee2aaSAndroid Build Coastguard Worker     // TODO: Should we add an optional flag to also allow purging of zero sized resources? Would we
68*c8dee2aaSAndroid Build Coastguard Worker     // want to be able to differentiate between things like Pipelines (probably never want to purge)
69*c8dee2aaSAndroid Build Coastguard Worker     // and things like descriptor sets.
70*c8dee2aaSAndroid Build Coastguard Worker     void purgeResourcesNotUsedSince(StdSteadyClock::time_point purgeTime);
71*c8dee2aaSAndroid Build Coastguard Worker 
72*c8dee2aaSAndroid Build Coastguard Worker     // Purge any unlocked resources. Resources that have a gpu memory size of zero will not be
73*c8dee2aaSAndroid Build Coastguard Worker     // purged.
74*c8dee2aaSAndroid Build Coastguard Worker     void purgeResources();
75*c8dee2aaSAndroid Build Coastguard Worker 
76*c8dee2aaSAndroid Build Coastguard Worker     // Called by the ResourceProvider when it is dropping its ref to the ResourceCache. After this
77*c8dee2aaSAndroid Build Coastguard Worker     // is called no more Resources can be returned to the ResourceCache (besides those already in
78*c8dee2aaSAndroid Build Coastguard Worker     // the return queue). Also no new Resources can be retrieved from the ResourceCache.
79*c8dee2aaSAndroid Build Coastguard Worker     void shutdown();
80*c8dee2aaSAndroid Build Coastguard Worker 
getMaxBudget()81*c8dee2aaSAndroid Build Coastguard Worker     size_t getMaxBudget() const { return fMaxBytes; }
82*c8dee2aaSAndroid Build Coastguard Worker 
currentBudgetedBytes()83*c8dee2aaSAndroid Build Coastguard Worker     size_t currentBudgetedBytes() const { return fBudgetedBytes; }
84*c8dee2aaSAndroid Build Coastguard Worker 
currentPurgeableBytes()85*c8dee2aaSAndroid Build Coastguard Worker     size_t currentPurgeableBytes() const { return fPurgeableBytes; }
86*c8dee2aaSAndroid Build Coastguard Worker 
87*c8dee2aaSAndroid Build Coastguard Worker     void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const;
88*c8dee2aaSAndroid Build Coastguard Worker 
89*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
forceProcessReturnedResources()90*c8dee2aaSAndroid Build Coastguard Worker     void forceProcessReturnedResources() { this->processReturnedResources(); }
91*c8dee2aaSAndroid Build Coastguard Worker 
forcePurgeAsNeeded()92*c8dee2aaSAndroid Build Coastguard Worker     void forcePurgeAsNeeded() { this->purgeAsNeeded(); }
93*c8dee2aaSAndroid Build Coastguard Worker 
94*c8dee2aaSAndroid Build Coastguard Worker     // Returns the numbers of Resources that can currently be found in the cache. This includes all
95*c8dee2aaSAndroid Build Coastguard Worker     // shared Resources and all non-shareable resources that have been returned to the cache.
96*c8dee2aaSAndroid Build Coastguard Worker     int numFindableResources() const;
97*c8dee2aaSAndroid Build Coastguard Worker 
98*c8dee2aaSAndroid Build Coastguard Worker     // This will probably end up being a public function to change the current budget size, but for
99*c8dee2aaSAndroid Build Coastguard Worker     // now just making this a testing only function.
100*c8dee2aaSAndroid Build Coastguard Worker     void setMaxBudget(size_t bytes);
101*c8dee2aaSAndroid Build Coastguard Worker 
102*c8dee2aaSAndroid Build Coastguard Worker     Resource* topOfPurgeableQueue();
103*c8dee2aaSAndroid Build Coastguard Worker 
testingInPurgeableQueue(Resource * resource)104*c8dee2aaSAndroid Build Coastguard Worker     bool testingInPurgeableQueue(Resource* resource) { return this->inPurgeableQueue(resource); }
105*c8dee2aaSAndroid Build Coastguard Worker 
106*c8dee2aaSAndroid Build Coastguard Worker     void visitTextures(const std::function<void(const Texture*, bool purgeable)>&) const;
107*c8dee2aaSAndroid Build Coastguard Worker #endif
108*c8dee2aaSAndroid Build Coastguard Worker 
proxyCache()109*c8dee2aaSAndroid Build Coastguard Worker     ProxyCache* proxyCache() { return fProxyCache.get(); }
110*c8dee2aaSAndroid Build Coastguard Worker 
111*c8dee2aaSAndroid Build Coastguard Worker private:
112*c8dee2aaSAndroid Build Coastguard Worker     ResourceCache(SingleOwner*, uint32_t recorderID, size_t maxBytes);
113*c8dee2aaSAndroid Build Coastguard Worker 
114*c8dee2aaSAndroid Build Coastguard Worker     // All these private functions are not meant to be thread safe. We don't check for is single
115*c8dee2aaSAndroid Build Coastguard Worker     // owner in them as we assume that has already been checked by the public api calls.
116*c8dee2aaSAndroid Build Coastguard Worker     void refAndMakeResourceMRU(Resource*);
117*c8dee2aaSAndroid Build Coastguard Worker     void addToNonpurgeableArray(Resource* resource);
118*c8dee2aaSAndroid Build Coastguard Worker     void removeFromNonpurgeableArray(Resource* resource);
119*c8dee2aaSAndroid Build Coastguard Worker     void removeFromPurgeableQueue(Resource* resource);
120*c8dee2aaSAndroid Build Coastguard Worker 
121*c8dee2aaSAndroid Build Coastguard Worker     // This will return true if any resources were actually returned to the cache
122*c8dee2aaSAndroid Build Coastguard Worker     bool processReturnedResources();
123*c8dee2aaSAndroid Build Coastguard Worker     void returnResourceToCache(Resource*, LastRemovedRef);
124*c8dee2aaSAndroid Build Coastguard Worker 
125*c8dee2aaSAndroid Build Coastguard Worker     uint32_t getNextTimestamp();
126*c8dee2aaSAndroid Build Coastguard Worker     void setResourceTimestamp(Resource*, uint32_t timestamp);
127*c8dee2aaSAndroid Build Coastguard Worker 
128*c8dee2aaSAndroid Build Coastguard Worker     bool inPurgeableQueue(Resource*) const;
129*c8dee2aaSAndroid Build Coastguard Worker 
overbudget()130*c8dee2aaSAndroid Build Coastguard Worker     bool overbudget() const { return fBudgetedBytes > fMaxBytes; }
131*c8dee2aaSAndroid Build Coastguard Worker     void purgeAsNeeded();
132*c8dee2aaSAndroid Build Coastguard Worker     void purgeResource(Resource*);
133*c8dee2aaSAndroid Build Coastguard Worker     // Passing in a nullptr for purgeTime will trigger us to try and free all unlocked resources.
134*c8dee2aaSAndroid Build Coastguard Worker     void purgeResources(const StdSteadyClock::time_point* purgeTime);
135*c8dee2aaSAndroid Build Coastguard Worker 
136*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
137*c8dee2aaSAndroid Build Coastguard Worker     bool isInCache(const Resource* r) const;
138*c8dee2aaSAndroid Build Coastguard Worker     void validate() const;
139*c8dee2aaSAndroid Build Coastguard Worker #else
validate()140*c8dee2aaSAndroid Build Coastguard Worker     void validate() const {}
141*c8dee2aaSAndroid Build Coastguard Worker #endif
142*c8dee2aaSAndroid Build Coastguard Worker 
143*c8dee2aaSAndroid Build Coastguard Worker     struct MapTraits {
144*c8dee2aaSAndroid Build Coastguard Worker         static const GraphiteResourceKey& GetKey(const Resource& r);
145*c8dee2aaSAndroid Build Coastguard Worker 
146*c8dee2aaSAndroid Build Coastguard Worker         static uint32_t Hash(const GraphiteResourceKey& key);
OnFreeMapTraits147*c8dee2aaSAndroid Build Coastguard Worker         static void OnFree(Resource*) {}
148*c8dee2aaSAndroid Build Coastguard Worker     };
149*c8dee2aaSAndroid Build Coastguard Worker     typedef SkTMultiMap<Resource, GraphiteResourceKey, MapTraits> ResourceMap;
150*c8dee2aaSAndroid Build Coastguard Worker 
151*c8dee2aaSAndroid Build Coastguard Worker     static bool CompareTimestamp(Resource* const& a, Resource* const& b);
152*c8dee2aaSAndroid Build Coastguard Worker     static int* AccessResourceIndex(Resource* const& res);
153*c8dee2aaSAndroid Build Coastguard Worker 
154*c8dee2aaSAndroid Build Coastguard Worker     using PurgeableQueue = SkTDPQueue<Resource*, CompareTimestamp, AccessResourceIndex>;
155*c8dee2aaSAndroid Build Coastguard Worker     using ResourceArray = SkTDArray<Resource*>;
156*c8dee2aaSAndroid Build Coastguard Worker 
157*c8dee2aaSAndroid Build Coastguard Worker     // Whenever a resource is added to the cache or the result of a cache lookup, fTimestamp is
158*c8dee2aaSAndroid Build Coastguard Worker     // assigned as the resource's timestamp and then incremented. fPurgeableQueue orders the
159*c8dee2aaSAndroid Build Coastguard Worker     // purgeable resources by this value, and thus is used to purge resources in LRU order.
160*c8dee2aaSAndroid Build Coastguard Worker     // Resources with a size of zero are set to have max uint32_t value. This will also put them at
161*c8dee2aaSAndroid Build Coastguard Worker     // the end of the LRU priority queue. This will allow us to not purge these resources even when
162*c8dee2aaSAndroid Build Coastguard Worker     // we are over budget.
163*c8dee2aaSAndroid Build Coastguard Worker     uint32_t fTimestamp = 0;
164*c8dee2aaSAndroid Build Coastguard Worker     static const uint32_t kMaxTimestamp = 0xFFFFFFFF;
165*c8dee2aaSAndroid Build Coastguard Worker 
166*c8dee2aaSAndroid Build Coastguard Worker     PurgeableQueue fPurgeableQueue;
167*c8dee2aaSAndroid Build Coastguard Worker     ResourceArray fNonpurgeableResources;
168*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<ProxyCache> fProxyCache;
169*c8dee2aaSAndroid Build Coastguard Worker 
170*c8dee2aaSAndroid Build Coastguard Worker     SkDEBUGCODE(int fCount = 0;)
171*c8dee2aaSAndroid Build Coastguard Worker 
172*c8dee2aaSAndroid Build Coastguard Worker     ResourceMap fResourceMap;
173*c8dee2aaSAndroid Build Coastguard Worker 
174*c8dee2aaSAndroid Build Coastguard Worker     // Our budget
175*c8dee2aaSAndroid Build Coastguard Worker     size_t fMaxBytes;
176*c8dee2aaSAndroid Build Coastguard Worker     size_t fBudgetedBytes = 0;
177*c8dee2aaSAndroid Build Coastguard Worker 
178*c8dee2aaSAndroid Build Coastguard Worker     size_t fPurgeableBytes = 0;
179*c8dee2aaSAndroid Build Coastguard Worker 
180*c8dee2aaSAndroid Build Coastguard Worker     SingleOwner* fSingleOwner = nullptr;
181*c8dee2aaSAndroid Build Coastguard Worker 
182*c8dee2aaSAndroid Build Coastguard Worker     bool fIsShutdown = false;
183*c8dee2aaSAndroid Build Coastguard Worker 
184*c8dee2aaSAndroid Build Coastguard Worker     SkMutex fReturnMutex;
185*c8dee2aaSAndroid Build Coastguard Worker     using ReturnQueue = std::vector<std::pair<Resource*, LastRemovedRef>>;
186*c8dee2aaSAndroid Build Coastguard Worker     ReturnQueue fReturnQueue SK_GUARDED_BY(fReturnMutex);
187*c8dee2aaSAndroid Build Coastguard Worker };
188*c8dee2aaSAndroid Build Coastguard Worker 
189*c8dee2aaSAndroid Build Coastguard Worker } // namespace skgpu::graphite
190*c8dee2aaSAndroid Build Coastguard Worker 
191*c8dee2aaSAndroid Build Coastguard Worker #endif // skgpu_graphite_ResourceCache_DEFINED
192