Flutter Engine
The Flutter Engine
Classes | Public Member Functions | Static Public Member Functions | List of all members
skgpu::graphite::ResourceCache Class Reference

#include <ResourceCache.h>

Inheritance diagram for skgpu::graphite::ResourceCache:
SkRefCnt SkRefCntBase

Public Member Functions

 ~ResourceCache () override
 
 ResourceCache (const ResourceCache &)=delete
 
 ResourceCache (ResourceCache &&)=delete
 
ResourceCacheoperator= (const ResourceCache &)=delete
 
ResourceCacheoperator= (ResourceCache &&)=delete
 
int getResourceCount () const
 
void insertResource (Resource *)
 
ResourcefindAndRefResource (const GraphiteResourceKey &key, skgpu::Budgeted)
 
bool returnResource (Resource *, LastRemovedRef)
 
void purgeResourcesNotUsedSince (StdSteadyClock::time_point purgeTime)
 
void purgeResources ()
 
void shutdown ()
 
size_t getMaxBudget () const
 
size_t currentBudgetedBytes () const
 
void dumpMemoryStatistics (SkTraceMemoryDump *traceMemoryDump) const
 
ProxyCacheproxyCache ()
 
- Public Member Functions inherited from SkRefCntBase
 SkRefCntBase ()
 
virtual ~SkRefCntBase ()
 
bool unique () const
 
void ref () const
 
void unref () const
 

Static Public Member Functions

static sk_sp< ResourceCacheMake (SingleOwner *, uint32_t recorderID, size_t maxBytes)
 

Detailed Description

Definition at line 41 of file ResourceCache.h.

Constructor & Destructor Documentation

◆ ~ResourceCache()

skgpu::graphite::ResourceCache::~ResourceCache ( )
override

Definition at line 45 of file ResourceCache.cpp.

45 {
46 // The ResourceCache must have been shutdown by the ResourceProvider before it is destroyed.
47 SkASSERT(fIsShutdown);
48}
#define SkASSERT(cond)
Definition: SkAssert.h:116

◆ ResourceCache() [1/2]

skgpu::graphite::ResourceCache::ResourceCache ( const ResourceCache )
delete

◆ ResourceCache() [2/2]

skgpu::graphite::ResourceCache::ResourceCache ( ResourceCache &&  )
delete

Member Function Documentation

◆ currentBudgetedBytes()

size_t skgpu::graphite::ResourceCache::currentBudgetedBytes ( ) const
inline

Definition at line 83 of file ResourceCache.h.

83{ return fBudgetedBytes; }

◆ dumpMemoryStatistics()

void skgpu::graphite::ResourceCache::dumpMemoryStatistics ( SkTraceMemoryDump traceMemoryDump) const

Definition at line 558 of file ResourceCache.cpp.

558 {
559 for (int i = 0; i < fNonpurgeableResources.size(); ++i) {
560 fNonpurgeableResources[i]->dumpMemoryStatistics(traceMemoryDump);
561 }
562 for (int i = 0; i < fPurgeableQueue.count(); ++i) {
563 fPurgeableQueue.at(i)->dumpMemoryStatistics(traceMemoryDump);
564 }
565}
int size() const
Definition: SkTDArray.h:138
int count() const
Definition: SkTDPQueue.h:45
T at(int i) const
Definition: SkTDPQueue.h:110

◆ findAndRefResource()

Resource * skgpu::graphite::ResourceCache::findAndRefResource ( const GraphiteResourceKey key,
skgpu::Budgeted  budgeted 
)

Definition at line 126 of file ResourceCache.cpp.

127 {
129
130 SkASSERT(key.isValid());
131
132 Resource* resource = fResourceMap.find(key);
133 if (!resource) {
134 // The main reason to call processReturnedResources in this call is to see if there are any
135 // resources that we could match with the key. However, there is overhead into calling it.
136 // So we only call it if we first failed to find a matching resource.
137 if (this->processReturnedResources()) {
138 resource = fResourceMap.find(key);
139 }
140 }
141 if (resource) {
142 // All resources we pull out of the cache for use should be budgeted
144 if (key.shareable() == Shareable::kNo) {
145 // If a resource is not shareable (i.e. scratch resource) then we remove it from the map
146 // so that it isn't found again.
147 fResourceMap.remove(key, resource);
148 if (budgeted == skgpu::Budgeted::kNo) {
149 resource->makeUnbudgeted();
150 fBudgetedBytes -= resource->gpuMemorySize();
151 }
152 SkDEBUGCODE(resource->fNonShareableInCache = false;)
153 } else {
154 // Shareable resources should never be requested as non budgeted
155 SkASSERT(budgeted == skgpu::Budgeted::kYes);
156 }
157 this->refAndMakeResourceMRU(resource);
158 this->validate();
159 }
160
161 // processReturnedResources may have added resources back into our budget if they were being
162 // using in an SkImage or SkSurface previously. However, instead of calling purgeAsNeeded in
163 // processReturnedResources, we delay calling it until now so we don't end up purging a resource
164 // we're looking for in this function.
165 //
166 // We could avoid calling this if we didn't return any resources from processReturnedResources.
167 // However, when not overbudget purgeAsNeeded is very cheap. When overbudget there may be some
168 // really niche usage patterns that could cause us to never actually return resources to the
169 // cache, but still be overbudget due to shared resources. So to be safe we just always call it
170 // here.
171 this->purgeAsNeeded();
172
173 return resource;
174}
#define ASSERT_SINGLE_OWNER
static SkString resource(SkPDFResourceType type, int index)
int find(const char substring[]) const
Definition: SkString.h:158

◆ getMaxBudget()

size_t skgpu::graphite::ResourceCache::getMaxBudget ( ) const
inline

Definition at line 81 of file ResourceCache.h.

81{ return fMaxBytes; }

◆ getResourceCount()

int skgpu::graphite::ResourceCache::getResourceCount ( ) const
inline

Definition at line 52 of file ResourceCache.h.

52 {
53 return fPurgeableQueue.count() + fNonpurgeableResources.size();
54 }

◆ insertResource()

void skgpu::graphite::ResourceCache::insertResource ( Resource resource)

Definition at line 82 of file ResourceCache.cpp.

82 {
85 SkASSERT(!this->isInCache(resource));
86 SkASSERT(!resource->wasDestroyed());
87 SkASSERT(!resource->isPurgeable());
88 SkASSERT(resource->key().isValid());
89 // All resources in the cache are owned. If we track wrapped resources in the cache we'll need
90 // to update this check.
91 SkASSERT(resource->ownership() == Ownership::kOwned);
92
93 // The reason to call processReturnedResources here is to get an accurate accounting of our
94 // memory usage as some resources can go from unbudgeted to budgeted when they return. So we
95 // want to have them all returned before adding the budget for the new resource in case we need
96 // to purge things. However, if the new resource has a memory size of 0, then we just skip
97 // returning resources (which has overhead for each call) since the new resource won't be
98 // affecting whether we're over or under budget.
99 if (resource->gpuMemorySize() > 0) {
100 this->processReturnedResources();
101 }
102
103 resource->registerWithCache(sk_ref_sp(this));
104 resource->refCache();
105
106 // We must set the timestamp before adding to the array in case the timestamp wraps and we wind
107 // up iterating over all the resources that already have timestamps.
108 this->setResourceTimestamp(resource, this->getNextTimestamp());
109 resource->updateAccessTime();
110
111 this->addToNonpurgeableArray(resource);
112
113 SkDEBUGCODE(fCount++;)
114
115 if (resource->key().shareable() == Shareable::kYes) {
116 fResourceMap.insert(resource->key(), resource);
117 }
118
119 if (resource->budgeted() == skgpu::Budgeted::kYes) {
120 fBudgetedBytes += resource->gpuMemorySize();
121 }
122
123 this->purgeAsNeeded();
124}
sk_sp< T > sk_ref_sp(T *obj)
Definition: SkRefCnt.h:381

◆ Make()

sk_sp< ResourceCache > skgpu::graphite::ResourceCache::Make ( SingleOwner singleOwner,
uint32_t  recorderID,
size_t  maxBytes 
)
static

Definition at line 26 of file ResourceCache.cpp.

28 {
29 return sk_sp<ResourceCache>(new ResourceCache(singleOwner, recorderID, maxBytes));
30}
ResourceCache(const ResourceCache &)=delete

◆ operator=() [1/2]

ResourceCache & skgpu::graphite::ResourceCache::operator= ( const ResourceCache )
delete

◆ operator=() [2/2]

ResourceCache & skgpu::graphite::ResourceCache::operator= ( ResourceCache &&  )
delete

◆ proxyCache()

ProxyCache * skgpu::graphite::ResourceCache::proxyCache ( )
inline

Definition at line 107 of file ResourceCache.h.

107{ return fProxyCache.get(); }

◆ purgeResources()

void skgpu::graphite::ResourceCache::purgeResources ( )

Definition at line 435 of file ResourceCache.cpp.

435 {
437 this->purgeResources(nullptr);
438}

◆ purgeResourcesNotUsedSince()

void skgpu::graphite::ResourceCache::purgeResourcesNotUsedSince ( StdSteadyClock::time_point  purgeTime)

Definition at line 430 of file ResourceCache.cpp.

430 {
432 this->purgeResources(&purgeTime);
433}

◆ returnResource()

bool skgpu::graphite::ResourceCache::returnResource ( Resource resource,
LastRemovedRef  removedRef 
)

Definition at line 191 of file ResourceCache.cpp.

191 {
192 // We should never be trying to return a LastRemovedRef of kCache.
193 SkASSERT(removedRef != LastRemovedRef::kCache);
194 SkAutoMutexExclusive locked(fReturnMutex);
195 if (fIsShutdown) {
196 return false;
197 }
198
200
201 // When a non-shareable resource's CB and Usage refs are both zero, give it a chance prepare
202 // itself to be reused. On Dawn/WebGPU we use this to remap kXferCpuToGpu buffers asynchronously
203 // so that they are already mapped before they come out of the cache again.
204 if (resource->shouldDeleteASAP() == Resource::DeleteASAP::kNo &&
205 resource->key().shareable() == Shareable::kNo &&
206 removedRef == LastRemovedRef::kUsage) {
207 resource->prepareForReturnToCache([resource] { resource->initialUsageRef(); });
208 // Check if resource was re-ref'ed. In that case exit without adding to the queue.
209 if (resource->hasUsageRef()) {
210 return true;
211 }
212 }
213
214 // We only allow one instance of a Resource to be in the return queue at a time. We do this so
215 // that the ReturnQueue stays small and quick to process.
216 //
217 // Because we take CacheRefs to all Resources added to the ReturnQueue, we would be safe if we
218 // decided to have multiple instances of a Resource. Even if an earlier returned instance of a
219 // Resource triggers that Resource to get purged from the cache, the Resource itself wouldn't
220 // get deleted until we drop all the CacheRefs in this ReturnQueue.
221 if (*resource->accessReturnIndex() >= 0) {
222 // If the resource is already in the return queue we promote the LastRemovedRef to be
223 // kUsage if that is what is returned here.
224 if (removedRef == LastRemovedRef::kUsage) {
225 SkASSERT(*resource->accessReturnIndex() < (int)fReturnQueue.size());
226 fReturnQueue[*resource->accessReturnIndex()].second = removedRef;
227 }
228 return true;
229 }
230#ifdef SK_DEBUG
231 for (auto& nextResource : fReturnQueue) {
232 SkASSERT(nextResource.first != resource);
233 }
234#endif
235
236 fReturnQueue.push_back(std::make_pair(resource, removedRef));
237 *resource->accessReturnIndex() = fReturnQueue.size() - 1;
238 resource->refCache();
239 return true;
240}
size_t size() const
Definition: SkString.h:131

◆ shutdown()

void skgpu::graphite::ResourceCache::shutdown ( )

Definition at line 50 of file ResourceCache.cpp.

50 {
52
53 SkASSERT(!fIsShutdown);
54
55 {
56 SkAutoMutexExclusive locked(fReturnMutex);
57 fIsShutdown = true;
58 }
59 if (fProxyCache) {
60 fProxyCache->purgeAll();
61 }
62
63 this->processReturnedResources();
64
65 while (fNonpurgeableResources.size()) {
66 Resource* back = *(fNonpurgeableResources.end() - 1);
67 SkASSERT(!back->wasDestroyed());
68 this->removeFromNonpurgeableArray(back);
69 back->unrefCache();
70 }
71
72 while (fPurgeableQueue.count()) {
73 Resource* top = fPurgeableQueue.peek();
74 SkASSERT(!top->wasDestroyed());
75 this->removeFromPurgeableQueue(top);
76 top->unrefCache();
77 }
78
80}
#define TRACE_EVENT_SCOPE_THREAD
#define TRACE_FUNC
Definition: SkTraceEvent.h:30
T * end()
Definition: SkTDArray.h:152
const T & peek() const
Definition: SkTDPQueue.h:48
#define TRACE_EVENT_INSTANT0(category_group, name)
Definition: trace_event.h:175

The documentation for this class was generated from the following files: