1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2014 Google Inc.
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 GrResourceCache_DEFINED
9*c8dee2aaSAndroid Build Coastguard Worker #define GrResourceCache_DEFINED
10*c8dee2aaSAndroid Build Coastguard Worker
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrDirectContext.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTArray.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTDArray.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTo.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/gpu/ganesh/GrTypesPriv.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkTDPQueue.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkMessageBus.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkTDynamicHash.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkTMultiMap.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/GpuTypesPriv.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ResourceKey.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrGpuResource.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrGpuResourceCacheAccess.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrGpuResourcePriv.h"
28*c8dee2aaSAndroid Build Coastguard Worker
29*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef>
30*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
31*c8dee2aaSAndroid Build Coastguard Worker #include <functional>
32*c8dee2aaSAndroid Build Coastguard Worker #include <type_traits>
33*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
34*c8dee2aaSAndroid Build Coastguard Worker
35*c8dee2aaSAndroid Build Coastguard Worker class GrProxyProvider;
36*c8dee2aaSAndroid Build Coastguard Worker class GrSurface;
37*c8dee2aaSAndroid Build Coastguard Worker class GrThreadSafeCache;
38*c8dee2aaSAndroid Build Coastguard Worker class SkString;
39*c8dee2aaSAndroid Build Coastguard Worker class SkTraceMemoryDump;
40*c8dee2aaSAndroid Build Coastguard Worker enum class GrPurgeResourceOptions;
41*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu {
42*c8dee2aaSAndroid Build Coastguard Worker class SingleOwner;
43*c8dee2aaSAndroid Build Coastguard Worker }
44*c8dee2aaSAndroid Build Coastguard Worker
45*c8dee2aaSAndroid Build Coastguard Worker /**
46*c8dee2aaSAndroid Build Coastguard Worker * Manages the lifetime of all GrGpuResource instances.
47*c8dee2aaSAndroid Build Coastguard Worker *
48*c8dee2aaSAndroid Build Coastguard Worker * Resources may have optionally have two types of keys:
49*c8dee2aaSAndroid Build Coastguard Worker * 1) A scratch key. This is for resources whose allocations are cached but not their contents.
50*c8dee2aaSAndroid Build Coastguard Worker * Multiple resources can share the same scratch key. This is so a caller can have two
51*c8dee2aaSAndroid Build Coastguard Worker * resource instances with the same properties (e.g. multipass rendering that ping-pongs
52*c8dee2aaSAndroid Build Coastguard Worker * between two temporary surfaces). The scratch key is set at resource creation time and
53*c8dee2aaSAndroid Build Coastguard Worker * should never change. Resources need not have a scratch key.
54*c8dee2aaSAndroid Build Coastguard Worker * 2) A unique key. This key's meaning is specific to the domain that created the key. Only one
55*c8dee2aaSAndroid Build Coastguard Worker * resource may have a given unique key. The unique key can be set, cleared, or changed
56*c8dee2aaSAndroid Build Coastguard Worker * anytime after resource creation.
57*c8dee2aaSAndroid Build Coastguard Worker *
58*c8dee2aaSAndroid Build Coastguard Worker * A unique key always takes precedence over a scratch key when a resource has both types of keys.
59*c8dee2aaSAndroid Build Coastguard Worker * If a resource has neither key type then it will be deleted as soon as the last reference to it
60*c8dee2aaSAndroid Build Coastguard Worker * is dropped.
61*c8dee2aaSAndroid Build Coastguard Worker */
62*c8dee2aaSAndroid Build Coastguard Worker class GrResourceCache {
63*c8dee2aaSAndroid Build Coastguard Worker public:
64*c8dee2aaSAndroid Build Coastguard Worker GrResourceCache(skgpu::SingleOwner* owner,
65*c8dee2aaSAndroid Build Coastguard Worker GrDirectContext::DirectContextID owningContextID,
66*c8dee2aaSAndroid Build Coastguard Worker uint32_t familyID);
67*c8dee2aaSAndroid Build Coastguard Worker ~GrResourceCache();
68*c8dee2aaSAndroid Build Coastguard Worker
69*c8dee2aaSAndroid Build Coastguard Worker /**
70*c8dee2aaSAndroid Build Coastguard Worker * This is used to safely return a resource to the cache when the owner may be on another
71*c8dee2aaSAndroid Build Coastguard Worker * thread from GrDirectContext. If the context still exists then using this method ensures that
72*c8dee2aaSAndroid Build Coastguard Worker * the resource is received by the cache for processing (recycling or destruction) on the
73*c8dee2aaSAndroid Build Coastguard Worker * context's thread.
74*c8dee2aaSAndroid Build Coastguard Worker *
75*c8dee2aaSAndroid Build Coastguard Worker * This is templated as it is rather than simply taking sk_sp<GrGpuResource> in order to enforce
76*c8dee2aaSAndroid Build Coastguard Worker * that the caller passes an rvalue. If the caller doesn't move its ref into this function
77*c8dee2aaSAndroid Build Coastguard Worker * then it will retain ownership, defeating the purpose. (Note that sk_sp<GrGpuResource>&&
78*c8dee2aaSAndroid Build Coastguard Worker * doesn't work either because calling with sk_sp<GrSpecificResource> will create a temporary
79*c8dee2aaSAndroid Build Coastguard Worker * sk_sp<GrGpuResource> which is an rvalue).
80*c8dee2aaSAndroid Build Coastguard Worker */
81*c8dee2aaSAndroid Build Coastguard Worker template<typename T>
82*c8dee2aaSAndroid Build Coastguard Worker static std::enable_if_t<std::is_base_of_v<GrGpuResource, T>, void>
ReturnResourceFromThread(sk_sp<T> && resource,GrDirectContext::DirectContextID id)83*c8dee2aaSAndroid Build Coastguard Worker ReturnResourceFromThread(sk_sp<T>&& resource, GrDirectContext::DirectContextID id) {
84*c8dee2aaSAndroid Build Coastguard Worker UnrefResourceMessage msg(std::move(resource), id);
85*c8dee2aaSAndroid Build Coastguard Worker UnrefResourceMessage::Bus::Post(std::move(msg));
86*c8dee2aaSAndroid Build Coastguard Worker }
87*c8dee2aaSAndroid Build Coastguard Worker
88*c8dee2aaSAndroid Build Coastguard Worker // Default maximum number of bytes of gpu memory of budgeted resources in the cache.
89*c8dee2aaSAndroid Build Coastguard Worker static const size_t kDefaultMaxSize = 256 * (1 << 20);
90*c8dee2aaSAndroid Build Coastguard Worker
91*c8dee2aaSAndroid Build Coastguard Worker /** Used to access functionality needed by GrGpuResource for lifetime management. */
92*c8dee2aaSAndroid Build Coastguard Worker class ResourceAccess;
93*c8dee2aaSAndroid Build Coastguard Worker ResourceAccess resourceAccess();
94*c8dee2aaSAndroid Build Coastguard Worker
95*c8dee2aaSAndroid Build Coastguard Worker /** Unique ID of the owning GrContext. */
contextUniqueID()96*c8dee2aaSAndroid Build Coastguard Worker uint32_t contextUniqueID() const { return fContextUniqueID; }
97*c8dee2aaSAndroid Build Coastguard Worker
98*c8dee2aaSAndroid Build Coastguard Worker /** Sets the max gpu memory byte size of the cache. */
99*c8dee2aaSAndroid Build Coastguard Worker void setLimit(size_t bytes);
100*c8dee2aaSAndroid Build Coastguard Worker
101*c8dee2aaSAndroid Build Coastguard Worker /**
102*c8dee2aaSAndroid Build Coastguard Worker * Returns the number of resources.
103*c8dee2aaSAndroid Build Coastguard Worker */
getResourceCount()104*c8dee2aaSAndroid Build Coastguard Worker int getResourceCount() const {
105*c8dee2aaSAndroid Build Coastguard Worker return fPurgeableQueue.count() + fNonpurgeableResources.size();
106*c8dee2aaSAndroid Build Coastguard Worker }
107*c8dee2aaSAndroid Build Coastguard Worker
108*c8dee2aaSAndroid Build Coastguard Worker /**
109*c8dee2aaSAndroid Build Coastguard Worker * Returns the number of resources that count against the budget.
110*c8dee2aaSAndroid Build Coastguard Worker */
getBudgetedResourceCount()111*c8dee2aaSAndroid Build Coastguard Worker int getBudgetedResourceCount() const { return fBudgetedCount; }
112*c8dee2aaSAndroid Build Coastguard Worker
113*c8dee2aaSAndroid Build Coastguard Worker /**
114*c8dee2aaSAndroid Build Coastguard Worker * Returns the number of bytes consumed by resources.
115*c8dee2aaSAndroid Build Coastguard Worker */
getResourceBytes()116*c8dee2aaSAndroid Build Coastguard Worker size_t getResourceBytes() const { return fBytes; }
117*c8dee2aaSAndroid Build Coastguard Worker
118*c8dee2aaSAndroid Build Coastguard Worker /**
119*c8dee2aaSAndroid Build Coastguard Worker * Returns the number of bytes held by unlocked resources which are available for purging.
120*c8dee2aaSAndroid Build Coastguard Worker */
getPurgeableBytes()121*c8dee2aaSAndroid Build Coastguard Worker size_t getPurgeableBytes() const { return fPurgeableBytes; }
122*c8dee2aaSAndroid Build Coastguard Worker
123*c8dee2aaSAndroid Build Coastguard Worker /**
124*c8dee2aaSAndroid Build Coastguard Worker * Returns the number of bytes consumed by budgeted resources.
125*c8dee2aaSAndroid Build Coastguard Worker */
getBudgetedResourceBytes()126*c8dee2aaSAndroid Build Coastguard Worker size_t getBudgetedResourceBytes() const { return fBudgetedBytes; }
127*c8dee2aaSAndroid Build Coastguard Worker
128*c8dee2aaSAndroid Build Coastguard Worker /**
129*c8dee2aaSAndroid Build Coastguard Worker * Returns the number of bytes consumed by cached resources.
130*c8dee2aaSAndroid Build Coastguard Worker */
getMaxResourceBytes()131*c8dee2aaSAndroid Build Coastguard Worker size_t getMaxResourceBytes() const { return fMaxBytes; }
132*c8dee2aaSAndroid Build Coastguard Worker
133*c8dee2aaSAndroid Build Coastguard Worker /**
134*c8dee2aaSAndroid Build Coastguard Worker * Abandons the backend API resources owned by all GrGpuResource objects and removes them from
135*c8dee2aaSAndroid Build Coastguard Worker * the cache.
136*c8dee2aaSAndroid Build Coastguard Worker */
137*c8dee2aaSAndroid Build Coastguard Worker void abandonAll();
138*c8dee2aaSAndroid Build Coastguard Worker
139*c8dee2aaSAndroid Build Coastguard Worker /**
140*c8dee2aaSAndroid Build Coastguard Worker * Releases the backend API resources owned by all GrGpuResource objects and removes them from
141*c8dee2aaSAndroid Build Coastguard Worker * the cache.
142*c8dee2aaSAndroid Build Coastguard Worker */
143*c8dee2aaSAndroid Build Coastguard Worker void releaseAll();
144*c8dee2aaSAndroid Build Coastguard Worker
145*c8dee2aaSAndroid Build Coastguard Worker /**
146*c8dee2aaSAndroid Build Coastguard Worker * Find a resource that matches a scratch key.
147*c8dee2aaSAndroid Build Coastguard Worker */
148*c8dee2aaSAndroid Build Coastguard Worker GrGpuResource* findAndRefScratchResource(const skgpu::ScratchKey& scratchKey);
149*c8dee2aaSAndroid Build Coastguard Worker
150*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
151*c8dee2aaSAndroid Build Coastguard Worker // This is not particularly fast and only used for validation, so debug only.
countScratchEntriesForKey(const skgpu::ScratchKey & scratchKey)152*c8dee2aaSAndroid Build Coastguard Worker int countScratchEntriesForKey(const skgpu::ScratchKey& scratchKey) const {
153*c8dee2aaSAndroid Build Coastguard Worker return fScratchMap.countForKey(scratchKey);
154*c8dee2aaSAndroid Build Coastguard Worker }
155*c8dee2aaSAndroid Build Coastguard Worker #endif
156*c8dee2aaSAndroid Build Coastguard Worker
157*c8dee2aaSAndroid Build Coastguard Worker /**
158*c8dee2aaSAndroid Build Coastguard Worker * Find a resource that matches a unique key.
159*c8dee2aaSAndroid Build Coastguard Worker */
findAndRefUniqueResource(const skgpu::UniqueKey & key)160*c8dee2aaSAndroid Build Coastguard Worker GrGpuResource* findAndRefUniqueResource(const skgpu::UniqueKey& key) {
161*c8dee2aaSAndroid Build Coastguard Worker GrGpuResource* resource = fUniqueHash.find(key);
162*c8dee2aaSAndroid Build Coastguard Worker if (resource) {
163*c8dee2aaSAndroid Build Coastguard Worker this->refAndMakeResourceMRU(resource);
164*c8dee2aaSAndroid Build Coastguard Worker }
165*c8dee2aaSAndroid Build Coastguard Worker return resource;
166*c8dee2aaSAndroid Build Coastguard Worker }
167*c8dee2aaSAndroid Build Coastguard Worker
168*c8dee2aaSAndroid Build Coastguard Worker /**
169*c8dee2aaSAndroid Build Coastguard Worker * Query whether a unique key exists in the cache.
170*c8dee2aaSAndroid Build Coastguard Worker */
hasUniqueKey(const skgpu::UniqueKey & key)171*c8dee2aaSAndroid Build Coastguard Worker bool hasUniqueKey(const skgpu::UniqueKey& key) const {
172*c8dee2aaSAndroid Build Coastguard Worker return SkToBool(fUniqueHash.find(key));
173*c8dee2aaSAndroid Build Coastguard Worker }
174*c8dee2aaSAndroid Build Coastguard Worker
175*c8dee2aaSAndroid Build Coastguard Worker /** Purges resources to become under budget and processes resources with invalidated unique
176*c8dee2aaSAndroid Build Coastguard Worker keys. */
177*c8dee2aaSAndroid Build Coastguard Worker void purgeAsNeeded();
178*c8dee2aaSAndroid Build Coastguard Worker
179*c8dee2aaSAndroid Build Coastguard Worker // Purge unlocked resources. If 'opts' is kScratchResourcesOnly, the purgeable resources
180*c8dee2aaSAndroid Build Coastguard Worker // containing persistent data are spared. If it is kAllResources then all purgeable resources
181*c8dee2aaSAndroid Build Coastguard Worker // will be deleted.
purgeUnlockedResources(GrPurgeResourceOptions opts)182*c8dee2aaSAndroid Build Coastguard Worker void purgeUnlockedResources(GrPurgeResourceOptions opts) {
183*c8dee2aaSAndroid Build Coastguard Worker this->purgeUnlockedResources(/*purgeTime=*/nullptr, opts);
184*c8dee2aaSAndroid Build Coastguard Worker }
185*c8dee2aaSAndroid Build Coastguard Worker
186*c8dee2aaSAndroid Build Coastguard Worker // Purge unlocked resources not used since the passed point in time. If 'opts' is
187*c8dee2aaSAndroid Build Coastguard Worker // kScratchResourcesOnly, the purgeable resources containing persistent data are spared.
188*c8dee2aaSAndroid Build Coastguard Worker // If it is kAllResources then all purgeable resources older than 'purgeTime' will be deleted.
purgeResourcesNotUsedSince(skgpu::StdSteadyClock::time_point purgeTime,GrPurgeResourceOptions opts)189*c8dee2aaSAndroid Build Coastguard Worker void purgeResourcesNotUsedSince(skgpu::StdSteadyClock::time_point purgeTime,
190*c8dee2aaSAndroid Build Coastguard Worker GrPurgeResourceOptions opts) {
191*c8dee2aaSAndroid Build Coastguard Worker this->purgeUnlockedResources(&purgeTime, opts);
192*c8dee2aaSAndroid Build Coastguard Worker }
193*c8dee2aaSAndroid Build Coastguard Worker
194*c8dee2aaSAndroid Build Coastguard Worker /** If it's possible to purge enough resources to get the provided amount of budget
195*c8dee2aaSAndroid Build Coastguard Worker headroom, do so and return true. If it's not possible, do nothing and return false.
196*c8dee2aaSAndroid Build Coastguard Worker */
197*c8dee2aaSAndroid Build Coastguard Worker bool purgeToMakeHeadroom(size_t desiredHeadroomBytes);
198*c8dee2aaSAndroid Build Coastguard Worker
overBudget()199*c8dee2aaSAndroid Build Coastguard Worker bool overBudget() const { return fBudgetedBytes > fMaxBytes; }
200*c8dee2aaSAndroid Build Coastguard Worker
201*c8dee2aaSAndroid Build Coastguard Worker /**
202*c8dee2aaSAndroid Build Coastguard Worker * Purge unlocked resources from the cache until the the provided byte count has been reached
203*c8dee2aaSAndroid Build Coastguard Worker * or we have purged all unlocked resources. The default policy is to purge in LRU order, but
204*c8dee2aaSAndroid Build Coastguard Worker * can be overridden to prefer purging scratch resources (in LRU order) prior to purging other
205*c8dee2aaSAndroid Build Coastguard Worker * resource types.
206*c8dee2aaSAndroid Build Coastguard Worker *
207*c8dee2aaSAndroid Build Coastguard Worker * @param maxBytesToPurge the desired number of bytes to be purged.
208*c8dee2aaSAndroid Build Coastguard Worker * @param preferScratchResources If true scratch resources will be purged prior to other
209*c8dee2aaSAndroid Build Coastguard Worker * resource types.
210*c8dee2aaSAndroid Build Coastguard Worker */
211*c8dee2aaSAndroid Build Coastguard Worker void purgeUnlockedResources(size_t bytesToPurge, bool preferScratchResources);
212*c8dee2aaSAndroid Build Coastguard Worker
213*c8dee2aaSAndroid Build Coastguard Worker /** Returns true if the cache would like a flush to occur in order to make more resources
214*c8dee2aaSAndroid Build Coastguard Worker purgeable. */
215*c8dee2aaSAndroid Build Coastguard Worker bool requestsFlush() const;
216*c8dee2aaSAndroid Build Coastguard Worker
217*c8dee2aaSAndroid Build Coastguard Worker #if GR_CACHE_STATS
218*c8dee2aaSAndroid Build Coastguard Worker struct Stats {
219*c8dee2aaSAndroid Build Coastguard Worker int fTotal;
220*c8dee2aaSAndroid Build Coastguard Worker int fNumPurgeable;
221*c8dee2aaSAndroid Build Coastguard Worker int fNumNonPurgeable;
222*c8dee2aaSAndroid Build Coastguard Worker
223*c8dee2aaSAndroid Build Coastguard Worker int fScratch;
224*c8dee2aaSAndroid Build Coastguard Worker int fWrapped;
225*c8dee2aaSAndroid Build Coastguard Worker size_t fUnbudgetedSize;
226*c8dee2aaSAndroid Build Coastguard Worker
StatsStats227*c8dee2aaSAndroid Build Coastguard Worker Stats() { this->reset(); }
228*c8dee2aaSAndroid Build Coastguard Worker
resetStats229*c8dee2aaSAndroid Build Coastguard Worker void reset() {
230*c8dee2aaSAndroid Build Coastguard Worker fTotal = 0;
231*c8dee2aaSAndroid Build Coastguard Worker fNumPurgeable = 0;
232*c8dee2aaSAndroid Build Coastguard Worker fNumNonPurgeable = 0;
233*c8dee2aaSAndroid Build Coastguard Worker fScratch = 0;
234*c8dee2aaSAndroid Build Coastguard Worker fWrapped = 0;
235*c8dee2aaSAndroid Build Coastguard Worker fUnbudgetedSize = 0;
236*c8dee2aaSAndroid Build Coastguard Worker }
237*c8dee2aaSAndroid Build Coastguard Worker
updateStats238*c8dee2aaSAndroid Build Coastguard Worker void update(GrGpuResource* resource) {
239*c8dee2aaSAndroid Build Coastguard Worker if (resource->cacheAccess().isScratch()) {
240*c8dee2aaSAndroid Build Coastguard Worker ++fScratch;
241*c8dee2aaSAndroid Build Coastguard Worker }
242*c8dee2aaSAndroid Build Coastguard Worker if (resource->resourcePriv().refsWrappedObjects()) {
243*c8dee2aaSAndroid Build Coastguard Worker ++fWrapped;
244*c8dee2aaSAndroid Build Coastguard Worker }
245*c8dee2aaSAndroid Build Coastguard Worker if (GrBudgetedType::kBudgeted != resource->resourcePriv().budgetedType()) {
246*c8dee2aaSAndroid Build Coastguard Worker fUnbudgetedSize += resource->gpuMemorySize();
247*c8dee2aaSAndroid Build Coastguard Worker }
248*c8dee2aaSAndroid Build Coastguard Worker }
249*c8dee2aaSAndroid Build Coastguard Worker };
250*c8dee2aaSAndroid Build Coastguard Worker
251*c8dee2aaSAndroid Build Coastguard Worker void getStats(Stats*) const;
252*c8dee2aaSAndroid Build Coastguard Worker
253*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
254*c8dee2aaSAndroid Build Coastguard Worker void dumpStats(SkString*) const;
255*c8dee2aaSAndroid Build Coastguard Worker
256*c8dee2aaSAndroid Build Coastguard Worker void dumpStatsKeyValuePairs(
257*c8dee2aaSAndroid Build Coastguard Worker skia_private::TArray<SkString>* keys, skia_private::TArray<double>* value) const;
258*c8dee2aaSAndroid Build Coastguard Worker #endif
259*c8dee2aaSAndroid Build Coastguard Worker
260*c8dee2aaSAndroid Build Coastguard Worker #endif // GR_CACHE_STATS
261*c8dee2aaSAndroid Build Coastguard Worker
262*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
263*c8dee2aaSAndroid Build Coastguard Worker int countUniqueKeysWithTag(const char* tag) const;
264*c8dee2aaSAndroid Build Coastguard Worker
265*c8dee2aaSAndroid Build Coastguard Worker void changeTimestamp(uint32_t newTimestamp);
266*c8dee2aaSAndroid Build Coastguard Worker
267*c8dee2aaSAndroid Build Coastguard Worker void visitSurfaces(const std::function<void(const GrSurface*, bool purgeable)>&) const;
268*c8dee2aaSAndroid Build Coastguard Worker #endif
269*c8dee2aaSAndroid Build Coastguard Worker
270*c8dee2aaSAndroid Build Coastguard Worker // Enumerates all cached resources and dumps their details to traceMemoryDump.
271*c8dee2aaSAndroid Build Coastguard Worker void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const;
272*c8dee2aaSAndroid Build Coastguard Worker
setProxyProvider(GrProxyProvider * proxyProvider)273*c8dee2aaSAndroid Build Coastguard Worker void setProxyProvider(GrProxyProvider* proxyProvider) { fProxyProvider = proxyProvider; }
setThreadSafeCache(GrThreadSafeCache * threadSafeCache)274*c8dee2aaSAndroid Build Coastguard Worker void setThreadSafeCache(GrThreadSafeCache* threadSafeCache) {
275*c8dee2aaSAndroid Build Coastguard Worker fThreadSafeCache = threadSafeCache;
276*c8dee2aaSAndroid Build Coastguard Worker }
277*c8dee2aaSAndroid Build Coastguard Worker
278*c8dee2aaSAndroid Build Coastguard Worker // It'd be nice if this could be private but SkMessageBus relies on macros to define types that
279*c8dee2aaSAndroid Build Coastguard Worker // require this to be public.
280*c8dee2aaSAndroid Build Coastguard Worker class UnrefResourceMessage {
281*c8dee2aaSAndroid Build Coastguard Worker public:
recipient()282*c8dee2aaSAndroid Build Coastguard Worker GrDirectContext::DirectContextID recipient() const { return fRecipient; }
283*c8dee2aaSAndroid Build Coastguard Worker
284*c8dee2aaSAndroid Build Coastguard Worker UnrefResourceMessage(UnrefResourceMessage&&) = default;
285*c8dee2aaSAndroid Build Coastguard Worker UnrefResourceMessage& operator=(UnrefResourceMessage&&) = default;
286*c8dee2aaSAndroid Build Coastguard Worker
287*c8dee2aaSAndroid Build Coastguard Worker private:
288*c8dee2aaSAndroid Build Coastguard Worker friend class GrResourceCache;
289*c8dee2aaSAndroid Build Coastguard Worker
290*c8dee2aaSAndroid Build Coastguard Worker using Bus = SkMessageBus<UnrefResourceMessage,
291*c8dee2aaSAndroid Build Coastguard Worker GrDirectContext::DirectContextID,
292*c8dee2aaSAndroid Build Coastguard Worker /*AllowCopyableMessage=*/false>;
293*c8dee2aaSAndroid Build Coastguard Worker
UnrefResourceMessage(sk_sp<GrGpuResource> && resource,GrDirectContext::DirectContextID recipient)294*c8dee2aaSAndroid Build Coastguard Worker UnrefResourceMessage(sk_sp<GrGpuResource>&& resource,
295*c8dee2aaSAndroid Build Coastguard Worker GrDirectContext::DirectContextID recipient)
296*c8dee2aaSAndroid Build Coastguard Worker : fResource(std::move(resource)), fRecipient(recipient) {}
297*c8dee2aaSAndroid Build Coastguard Worker
298*c8dee2aaSAndroid Build Coastguard Worker UnrefResourceMessage(const UnrefResourceMessage&) = delete;
299*c8dee2aaSAndroid Build Coastguard Worker UnrefResourceMessage& operator=(const UnrefResourceMessage&) = delete;
300*c8dee2aaSAndroid Build Coastguard Worker
301*c8dee2aaSAndroid Build Coastguard Worker sk_sp<GrGpuResource> fResource;
302*c8dee2aaSAndroid Build Coastguard Worker GrDirectContext::DirectContextID fRecipient;
303*c8dee2aaSAndroid Build Coastguard Worker };
304*c8dee2aaSAndroid Build Coastguard Worker
305*c8dee2aaSAndroid Build Coastguard Worker private:
306*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////
307*c8dee2aaSAndroid Build Coastguard Worker /// @name Methods accessible via ResourceAccess
308*c8dee2aaSAndroid Build Coastguard Worker ////
309*c8dee2aaSAndroid Build Coastguard Worker void insertResource(GrGpuResource*);
310*c8dee2aaSAndroid Build Coastguard Worker void removeResource(GrGpuResource*);
311*c8dee2aaSAndroid Build Coastguard Worker void notifyARefCntReachedZero(GrGpuResource*, GrGpuResource::LastRemovedRef);
312*c8dee2aaSAndroid Build Coastguard Worker void changeUniqueKey(GrGpuResource*, const skgpu::UniqueKey&);
313*c8dee2aaSAndroid Build Coastguard Worker void removeUniqueKey(GrGpuResource*);
314*c8dee2aaSAndroid Build Coastguard Worker void willRemoveScratchKey(const GrGpuResource*);
315*c8dee2aaSAndroid Build Coastguard Worker void didChangeBudgetStatus(GrGpuResource*);
316*c8dee2aaSAndroid Build Coastguard Worker void refResource(GrGpuResource* resource);
317*c8dee2aaSAndroid Build Coastguard Worker /// @}
318*c8dee2aaSAndroid Build Coastguard Worker
319*c8dee2aaSAndroid Build Coastguard Worker void refAndMakeResourceMRU(GrGpuResource*);
320*c8dee2aaSAndroid Build Coastguard Worker void processFreedGpuResources();
321*c8dee2aaSAndroid Build Coastguard Worker void addToNonpurgeableArray(GrGpuResource*);
322*c8dee2aaSAndroid Build Coastguard Worker void removeFromNonpurgeableArray(GrGpuResource*);
323*c8dee2aaSAndroid Build Coastguard Worker
wouldFit(size_t bytes)324*c8dee2aaSAndroid Build Coastguard Worker bool wouldFit(size_t bytes) const { return fBudgetedBytes+bytes <= fMaxBytes; }
325*c8dee2aaSAndroid Build Coastguard Worker
326*c8dee2aaSAndroid Build Coastguard Worker uint32_t getNextTimestamp();
327*c8dee2aaSAndroid Build Coastguard Worker
328*c8dee2aaSAndroid Build Coastguard Worker void purgeUnlockedResources(const skgpu::StdSteadyClock::time_point* purgeTime,
329*c8dee2aaSAndroid Build Coastguard Worker GrPurgeResourceOptions opts);
330*c8dee2aaSAndroid Build Coastguard Worker
331*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
332*c8dee2aaSAndroid Build Coastguard Worker bool isInCache(const GrGpuResource* r) const;
333*c8dee2aaSAndroid Build Coastguard Worker void validate() const;
334*c8dee2aaSAndroid Build Coastguard Worker #else
validate()335*c8dee2aaSAndroid Build Coastguard Worker void validate() const {}
336*c8dee2aaSAndroid Build Coastguard Worker #endif
337*c8dee2aaSAndroid Build Coastguard Worker
338*c8dee2aaSAndroid Build Coastguard Worker class AutoValidate;
339*c8dee2aaSAndroid Build Coastguard Worker
340*c8dee2aaSAndroid Build Coastguard Worker struct ScratchMapTraits {
GetKeyScratchMapTraits341*c8dee2aaSAndroid Build Coastguard Worker static const skgpu::ScratchKey& GetKey(const GrGpuResource& r) {
342*c8dee2aaSAndroid Build Coastguard Worker return r.resourcePriv().getScratchKey();
343*c8dee2aaSAndroid Build Coastguard Worker }
344*c8dee2aaSAndroid Build Coastguard Worker
HashScratchMapTraits345*c8dee2aaSAndroid Build Coastguard Worker static uint32_t Hash(const skgpu::ScratchKey& key) { return key.hash(); }
OnFreeScratchMapTraits346*c8dee2aaSAndroid Build Coastguard Worker static void OnFree(GrGpuResource*) { }
347*c8dee2aaSAndroid Build Coastguard Worker };
348*c8dee2aaSAndroid Build Coastguard Worker typedef SkTMultiMap<GrGpuResource, skgpu::ScratchKey, ScratchMapTraits> ScratchMap;
349*c8dee2aaSAndroid Build Coastguard Worker
350*c8dee2aaSAndroid Build Coastguard Worker struct UniqueHashTraits {
GetKeyUniqueHashTraits351*c8dee2aaSAndroid Build Coastguard Worker static const skgpu::UniqueKey& GetKey(const GrGpuResource& r) { return r.getUniqueKey(); }
352*c8dee2aaSAndroid Build Coastguard Worker
HashUniqueHashTraits353*c8dee2aaSAndroid Build Coastguard Worker static uint32_t Hash(const skgpu::UniqueKey& key) { return key.hash(); }
354*c8dee2aaSAndroid Build Coastguard Worker };
355*c8dee2aaSAndroid Build Coastguard Worker typedef SkTDynamicHash<GrGpuResource, skgpu::UniqueKey, UniqueHashTraits> UniqueHash;
356*c8dee2aaSAndroid Build Coastguard Worker
CompareTimestamp(GrGpuResource * const & a,GrGpuResource * const & b)357*c8dee2aaSAndroid Build Coastguard Worker static bool CompareTimestamp(GrGpuResource* const& a, GrGpuResource* const& b) {
358*c8dee2aaSAndroid Build Coastguard Worker return a->cacheAccess().timestamp() < b->cacheAccess().timestamp();
359*c8dee2aaSAndroid Build Coastguard Worker }
360*c8dee2aaSAndroid Build Coastguard Worker
AccessResourceIndex(GrGpuResource * const & res)361*c8dee2aaSAndroid Build Coastguard Worker static int* AccessResourceIndex(GrGpuResource* const& res) {
362*c8dee2aaSAndroid Build Coastguard Worker return res->cacheAccess().accessCacheIndex();
363*c8dee2aaSAndroid Build Coastguard Worker }
364*c8dee2aaSAndroid Build Coastguard Worker
365*c8dee2aaSAndroid Build Coastguard Worker typedef SkMessageBus<skgpu::UniqueKeyInvalidatedMessage, uint32_t>::Inbox InvalidUniqueKeyInbox;
366*c8dee2aaSAndroid Build Coastguard Worker typedef SkTDPQueue<GrGpuResource*, CompareTimestamp, AccessResourceIndex> PurgeableQueue;
367*c8dee2aaSAndroid Build Coastguard Worker typedef SkTDArray<GrGpuResource*> ResourceArray;
368*c8dee2aaSAndroid Build Coastguard Worker
369*c8dee2aaSAndroid Build Coastguard Worker GrProxyProvider* fProxyProvider = nullptr;
370*c8dee2aaSAndroid Build Coastguard Worker GrThreadSafeCache* fThreadSafeCache = nullptr;
371*c8dee2aaSAndroid Build Coastguard Worker
372*c8dee2aaSAndroid Build Coastguard Worker // Whenever a resource is added to the cache or the result of a cache lookup, fTimestamp is
373*c8dee2aaSAndroid Build Coastguard Worker // assigned as the resource's timestamp and then incremented. fPurgeableQueue orders the
374*c8dee2aaSAndroid Build Coastguard Worker // purgeable resources by this value, and thus is used to purge resources in LRU order.
375*c8dee2aaSAndroid Build Coastguard Worker uint32_t fTimestamp = 0;
376*c8dee2aaSAndroid Build Coastguard Worker PurgeableQueue fPurgeableQueue;
377*c8dee2aaSAndroid Build Coastguard Worker ResourceArray fNonpurgeableResources;
378*c8dee2aaSAndroid Build Coastguard Worker
379*c8dee2aaSAndroid Build Coastguard Worker // This map holds all resources that can be used as scratch resources.
380*c8dee2aaSAndroid Build Coastguard Worker ScratchMap fScratchMap;
381*c8dee2aaSAndroid Build Coastguard Worker // This holds all resources that have unique keys.
382*c8dee2aaSAndroid Build Coastguard Worker UniqueHash fUniqueHash;
383*c8dee2aaSAndroid Build Coastguard Worker
384*c8dee2aaSAndroid Build Coastguard Worker // our budget, used in purgeAsNeeded()
385*c8dee2aaSAndroid Build Coastguard Worker size_t fMaxBytes = kDefaultMaxSize;
386*c8dee2aaSAndroid Build Coastguard Worker
387*c8dee2aaSAndroid Build Coastguard Worker #if GR_CACHE_STATS
388*c8dee2aaSAndroid Build Coastguard Worker int fHighWaterCount = 0;
389*c8dee2aaSAndroid Build Coastguard Worker size_t fHighWaterBytes = 0;
390*c8dee2aaSAndroid Build Coastguard Worker int fBudgetedHighWaterCount = 0;
391*c8dee2aaSAndroid Build Coastguard Worker size_t fBudgetedHighWaterBytes = 0;
392*c8dee2aaSAndroid Build Coastguard Worker #endif
393*c8dee2aaSAndroid Build Coastguard Worker
394*c8dee2aaSAndroid Build Coastguard Worker // our current stats for all resources
395*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(int fCount = 0;)
396*c8dee2aaSAndroid Build Coastguard Worker size_t fBytes = 0;
397*c8dee2aaSAndroid Build Coastguard Worker
398*c8dee2aaSAndroid Build Coastguard Worker // our current stats for resources that count against the budget
399*c8dee2aaSAndroid Build Coastguard Worker int fBudgetedCount = 0;
400*c8dee2aaSAndroid Build Coastguard Worker size_t fBudgetedBytes = 0;
401*c8dee2aaSAndroid Build Coastguard Worker size_t fPurgeableBytes = 0;
402*c8dee2aaSAndroid Build Coastguard Worker int fNumBudgetedResourcesFlushWillMakePurgeable = 0;
403*c8dee2aaSAndroid Build Coastguard Worker
404*c8dee2aaSAndroid Build Coastguard Worker InvalidUniqueKeyInbox fInvalidUniqueKeyInbox;
405*c8dee2aaSAndroid Build Coastguard Worker UnrefResourceMessage::Bus::Inbox fUnrefResourceInbox;
406*c8dee2aaSAndroid Build Coastguard Worker
407*c8dee2aaSAndroid Build Coastguard Worker GrDirectContext::DirectContextID fOwningContextID;
408*c8dee2aaSAndroid Build Coastguard Worker uint32_t fContextUniqueID = SK_InvalidUniqueID;
409*c8dee2aaSAndroid Build Coastguard Worker skgpu::SingleOwner* fSingleOwner = nullptr;
410*c8dee2aaSAndroid Build Coastguard Worker
411*c8dee2aaSAndroid Build Coastguard Worker // This resource is allowed to be in the nonpurgeable array for the sake of validate() because
412*c8dee2aaSAndroid Build Coastguard Worker // we're in the midst of converting it to purgeable status.
413*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(GrGpuResource* fNewlyPurgeableResourceForValidation = nullptr;)
414*c8dee2aaSAndroid Build Coastguard Worker };
415*c8dee2aaSAndroid Build Coastguard Worker
416*c8dee2aaSAndroid Build Coastguard Worker class GrResourceCache::ResourceAccess {
417*c8dee2aaSAndroid Build Coastguard Worker private:
ResourceAccess(GrResourceCache * cache)418*c8dee2aaSAndroid Build Coastguard Worker ResourceAccess(GrResourceCache* cache) : fCache(cache) { }
ResourceAccess(const ResourceAccess & that)419*c8dee2aaSAndroid Build Coastguard Worker ResourceAccess(const ResourceAccess& that) : fCache(that.fCache) { }
420*c8dee2aaSAndroid Build Coastguard Worker ResourceAccess& operator=(const ResourceAccess&) = delete;
421*c8dee2aaSAndroid Build Coastguard Worker
422*c8dee2aaSAndroid Build Coastguard Worker /**
423*c8dee2aaSAndroid Build Coastguard Worker * Insert a resource into the cache.
424*c8dee2aaSAndroid Build Coastguard Worker */
insertResource(GrGpuResource * resource)425*c8dee2aaSAndroid Build Coastguard Worker void insertResource(GrGpuResource* resource) { fCache->insertResource(resource); }
426*c8dee2aaSAndroid Build Coastguard Worker
427*c8dee2aaSAndroid Build Coastguard Worker /**
428*c8dee2aaSAndroid Build Coastguard Worker * Removes a resource from the cache.
429*c8dee2aaSAndroid Build Coastguard Worker */
removeResource(GrGpuResource * resource)430*c8dee2aaSAndroid Build Coastguard Worker void removeResource(GrGpuResource* resource) { fCache->removeResource(resource); }
431*c8dee2aaSAndroid Build Coastguard Worker
432*c8dee2aaSAndroid Build Coastguard Worker /**
433*c8dee2aaSAndroid Build Coastguard Worker * Adds a ref to a resource with proper tracking if the resource has 0 refs prior to
434*c8dee2aaSAndroid Build Coastguard Worker * adding the ref.
435*c8dee2aaSAndroid Build Coastguard Worker */
refResource(GrGpuResource * resource)436*c8dee2aaSAndroid Build Coastguard Worker void refResource(GrGpuResource* resource) { fCache->refResource(resource); }
437*c8dee2aaSAndroid Build Coastguard Worker
438*c8dee2aaSAndroid Build Coastguard Worker /**
439*c8dee2aaSAndroid Build Coastguard Worker * Notifications that should be sent to the cache when the ref/io cnt status of resources
440*c8dee2aaSAndroid Build Coastguard Worker * changes.
441*c8dee2aaSAndroid Build Coastguard Worker */
442*c8dee2aaSAndroid Build Coastguard Worker enum RefNotificationFlags {
443*c8dee2aaSAndroid Build Coastguard Worker /** All types of refs on the resource have reached zero. */
444*c8dee2aaSAndroid Build Coastguard Worker kAllCntsReachedZero_RefNotificationFlag = 0x1,
445*c8dee2aaSAndroid Build Coastguard Worker /** The normal (not pending IO type) ref cnt has reached zero. */
446*c8dee2aaSAndroid Build Coastguard Worker kRefCntReachedZero_RefNotificationFlag = 0x2,
447*c8dee2aaSAndroid Build Coastguard Worker };
448*c8dee2aaSAndroid Build Coastguard Worker /**
449*c8dee2aaSAndroid Build Coastguard Worker * Called by GrGpuResources when they detect one of their ref cnts have reached zero. This may
450*c8dee2aaSAndroid Build Coastguard Worker * either be the main ref or the command buffer usage ref.
451*c8dee2aaSAndroid Build Coastguard Worker */
notifyARefCntReachedZero(GrGpuResource * resource,GrGpuResource::LastRemovedRef removedRef)452*c8dee2aaSAndroid Build Coastguard Worker void notifyARefCntReachedZero(GrGpuResource* resource,
453*c8dee2aaSAndroid Build Coastguard Worker GrGpuResource::LastRemovedRef removedRef) {
454*c8dee2aaSAndroid Build Coastguard Worker fCache->notifyARefCntReachedZero(resource, removedRef);
455*c8dee2aaSAndroid Build Coastguard Worker }
456*c8dee2aaSAndroid Build Coastguard Worker
457*c8dee2aaSAndroid Build Coastguard Worker /**
458*c8dee2aaSAndroid Build Coastguard Worker * Called by GrGpuResources to change their unique keys.
459*c8dee2aaSAndroid Build Coastguard Worker */
changeUniqueKey(GrGpuResource * resource,const skgpu::UniqueKey & newKey)460*c8dee2aaSAndroid Build Coastguard Worker void changeUniqueKey(GrGpuResource* resource, const skgpu::UniqueKey& newKey) {
461*c8dee2aaSAndroid Build Coastguard Worker fCache->changeUniqueKey(resource, newKey);
462*c8dee2aaSAndroid Build Coastguard Worker }
463*c8dee2aaSAndroid Build Coastguard Worker
464*c8dee2aaSAndroid Build Coastguard Worker /**
465*c8dee2aaSAndroid Build Coastguard Worker * Called by a GrGpuResource to remove its unique key.
466*c8dee2aaSAndroid Build Coastguard Worker */
removeUniqueKey(GrGpuResource * resource)467*c8dee2aaSAndroid Build Coastguard Worker void removeUniqueKey(GrGpuResource* resource) { fCache->removeUniqueKey(resource); }
468*c8dee2aaSAndroid Build Coastguard Worker
469*c8dee2aaSAndroid Build Coastguard Worker /**
470*c8dee2aaSAndroid Build Coastguard Worker * Called by a GrGpuResource when it removes its scratch key.
471*c8dee2aaSAndroid Build Coastguard Worker */
willRemoveScratchKey(const GrGpuResource * resource)472*c8dee2aaSAndroid Build Coastguard Worker void willRemoveScratchKey(const GrGpuResource* resource) {
473*c8dee2aaSAndroid Build Coastguard Worker fCache->willRemoveScratchKey(resource);
474*c8dee2aaSAndroid Build Coastguard Worker }
475*c8dee2aaSAndroid Build Coastguard Worker
476*c8dee2aaSAndroid Build Coastguard Worker /**
477*c8dee2aaSAndroid Build Coastguard Worker * Called by GrGpuResources when they change from budgeted to unbudgeted or vice versa.
478*c8dee2aaSAndroid Build Coastguard Worker */
didChangeBudgetStatus(GrGpuResource * resource)479*c8dee2aaSAndroid Build Coastguard Worker void didChangeBudgetStatus(GrGpuResource* resource) { fCache->didChangeBudgetStatus(resource); }
480*c8dee2aaSAndroid Build Coastguard Worker
481*c8dee2aaSAndroid Build Coastguard Worker // No taking addresses of this type.
482*c8dee2aaSAndroid Build Coastguard Worker const ResourceAccess* operator&() const;
483*c8dee2aaSAndroid Build Coastguard Worker ResourceAccess* operator&();
484*c8dee2aaSAndroid Build Coastguard Worker
485*c8dee2aaSAndroid Build Coastguard Worker GrResourceCache* fCache;
486*c8dee2aaSAndroid Build Coastguard Worker
487*c8dee2aaSAndroid Build Coastguard Worker friend class GrGpuResource; // To access all the proxy inline methods.
488*c8dee2aaSAndroid Build Coastguard Worker friend class GrResourceCache; // To create this type.
489*c8dee2aaSAndroid Build Coastguard Worker };
490*c8dee2aaSAndroid Build Coastguard Worker
SkShouldPostMessageToBus(const GrResourceCache::UnrefResourceMessage & msg,GrDirectContext::DirectContextID potentialRecipient)491*c8dee2aaSAndroid Build Coastguard Worker static inline bool SkShouldPostMessageToBus(const GrResourceCache::UnrefResourceMessage& msg,
492*c8dee2aaSAndroid Build Coastguard Worker GrDirectContext::DirectContextID potentialRecipient) {
493*c8dee2aaSAndroid Build Coastguard Worker return potentialRecipient == msg.recipient();
494*c8dee2aaSAndroid Build Coastguard Worker }
495*c8dee2aaSAndroid Build Coastguard Worker
resourceAccess()496*c8dee2aaSAndroid Build Coastguard Worker inline GrResourceCache::ResourceAccess GrResourceCache::resourceAccess() {
497*c8dee2aaSAndroid Build Coastguard Worker return ResourceAccess(this);
498*c8dee2aaSAndroid Build Coastguard Worker }
499*c8dee2aaSAndroid Build Coastguard Worker
500*c8dee2aaSAndroid Build Coastguard Worker #endif
501