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