Lines Matching full:resource
16 #include "src/gpu/graphite/Resource.h"
66 Resource* back = *(fNonpurgeableResources.end() - 1); in shutdown()
73 Resource* top = fPurgeableQueue.peek(); in shutdown()
82 void ResourceCache::insertResource(Resource* resource) { in insertResource() argument
84 SkASSERT(resource); in insertResource()
85 SkASSERT(!this->isInCache(resource)); in insertResource()
86 SkASSERT(!resource->wasDestroyed()); in insertResource()
87 SkASSERT(!resource->isPurgeable()); in insertResource()
88 SkASSERT(resource->key().isValid()); in insertResource()
91 SkASSERT(resource->ownership() == Ownership::kOwned); in insertResource()
94 resource->updateGpuMemorySize(); in insertResource()
98 // want to have them all returned before adding the budget for the new resource in case we need in insertResource()
99 // to purge things. However, if the new resource has a memory size of 0, then we just skip in insertResource()
100 // returning resources (which has overhead for each call) since the new resource won't be in insertResource()
102 if (resource->gpuMemorySize() > 0) { in insertResource()
106 resource->registerWithCache(sk_ref_sp(this)); in insertResource()
107 resource->refCache(); in insertResource()
111 this->setResourceTimestamp(resource, this->getNextTimestamp()); in insertResource()
112 resource->updateAccessTime(); in insertResource()
114 this->addToNonpurgeableArray(resource); in insertResource()
118 if (resource->key().shareable() == Shareable::kYes) { in insertResource()
119 fResourceMap.insert(resource->key(), resource); in insertResource()
122 if (resource->budgeted() == skgpu::Budgeted::kYes) { in insertResource()
123 fBudgetedBytes += resource->gpuMemorySize(); in insertResource()
129 Resource* ResourceCache::findAndRefResource(const GraphiteResourceKey& key, in findAndRefResource()
135 Resource* resource = fResourceMap.find(key); in findAndRefResource() local
136 if (!resource) { in findAndRefResource()
139 // So we only call it if we first failed to find a matching resource. in findAndRefResource()
141 resource = fResourceMap.find(key); in findAndRefResource()
144 if (resource) { in findAndRefResource()
146 SkASSERT(resource->budgeted() == skgpu::Budgeted::kYes); in findAndRefResource()
148 // If a resource is not shareable (i.e. scratch resource) then we remove it from the map in findAndRefResource()
150 fResourceMap.remove(key, resource); in findAndRefResource()
152 resource->makeUnbudgeted(); in findAndRefResource()
153 fBudgetedBytes -= resource->gpuMemorySize(); in findAndRefResource()
155 SkDEBUGCODE(resource->fNonShareableInCache = false;) in findAndRefResource()
160 this->refAndMakeResourceMRU(resource); in findAndRefResource()
166 // processReturnedResources, we delay calling it until now so we don't end up purging a resource in findAndRefResource()
176 return resource; in findAndRefResource()
179 void ResourceCache::refAndMakeResourceMRU(Resource* resource) { in refAndMakeResourceMRU() argument
180 SkASSERT(resource); in refAndMakeResourceMRU()
181 SkASSERT(this->isInCache(resource)); in refAndMakeResourceMRU()
183 if (this->inPurgeableQueue(resource)) { in refAndMakeResourceMRU()
185 this->removeFromPurgeableQueue(resource); in refAndMakeResourceMRU()
186 this->addToNonpurgeableArray(resource); in refAndMakeResourceMRU()
188 resource->initialUsageRef(); in refAndMakeResourceMRU()
190 this->setResourceTimestamp(resource, this->getNextTimestamp()); in refAndMakeResourceMRU()
194 bool ResourceCache::returnResource(Resource* resource, LastRemovedRef removedRef) { in returnResource() argument
202 SkASSERT(resource); in returnResource()
204 // When a non-shareable resource's CB and Usage refs are both zero, give it a chance prepare in returnResource()
207 if (resource->shouldDeleteASAP() == Resource::DeleteASAP::kNo && in returnResource()
208 resource->key().shareable() == Shareable::kNo && in returnResource()
210 resource->prepareForReturnToCache([resource] { resource->initialUsageRef(); }); in returnResource()
211 // Check if resource was re-ref'ed. In that case exit without adding to the queue. in returnResource()
212 if (resource->hasUsageRef()) { in returnResource()
217 // We only allow one instance of a Resource to be in the return queue at a time. We do this so in returnResource()
221 // decided to have multiple instances of a Resource. Even if an earlier returned instance of a in returnResource()
222 // Resource triggers that Resource to get purged from the cache, the Resource itself wouldn't in returnResource()
224 if (*resource->accessReturnIndex() >= 0) { in returnResource()
225 // If the resource is already in the return queue we promote the LastRemovedRef to be in returnResource()
228 SkASSERT(*resource->accessReturnIndex() < (int)fReturnQueue.size()); in returnResource()
229 fReturnQueue[*resource->accessReturnIndex()].second = removedRef; in returnResource()
235 SkASSERT(nextResource.first != resource); in returnResource()
239 fReturnQueue.push_back(std::make_pair(resource, removedRef)); in returnResource()
240 *resource->accessReturnIndex() = fReturnQueue.size() - 1; in returnResource()
241 resource->refCache(); in returnResource()
247 // so that we can drop the fReturnMutex. When we process a Resource we may need to grab its in processReturnedResources()
248 // UnrefMutex. This could cause a deadlock if on another thread the Resource has the UnrefMutex in processReturnedResources()
259 auto [resource, ref] = nextResource; in processReturnedResources()
260 SkASSERT(*resource->accessReturnIndex() >= 0); in processReturnedResources()
261 *resource->accessReturnIndex() = -1; in processReturnedResources()
273 auto [resource, ref] = nextResource; in processReturnedResources()
274 // We need this check here to handle the following scenario. A Resource is sitting in the in processReturnedResources()
275 // ReturnQueue (say from kUsage last ref) and the Resource still has a command buffer ref in processReturnedResources()
278 // thread. The Resource cannot be added to the ReturnQueue since the lock is held. Back in in processReturnedResources()
279 // the ResourceCache (we'll drop the ReturnMutex) and when we try to return the Resource we in processReturnedResources()
280 // will see that it is purgeable. If we are overbudget it is possible that the Resource gets in processReturnedResources()
282 // call will actually block here on the Resource's UnrefMutex which is held from the command in processReturnedResources()
286 // processReturnedResources the next time, we don't want this Resource added back into the in processReturnedResources()
287 // cache, thus we have the check here. The Resource will then get deleted when we call in processReturnedResources()
289 if (*resource->accessCacheIndex() != -1) { in processReturnedResources()
290 this->returnResourceToCache(resource, ref); in processReturnedResources()
293 resource->unrefCache(); in processReturnedResources()
298 void ResourceCache::returnResourceToCache(Resource* resource, LastRemovedRef removedRef) { in returnResourceToCache() argument
299 // A resource should not have been destroyed when placed into the return queue. Also before in returnResourceToCache()
302 // resources can be added. Thus we should not end up in a situation where a resource gets in returnResourceToCache()
304 SkASSERT(!resource->wasDestroyed()); in returnResourceToCache()
306 SkASSERT(this->isInCache(resource)); in returnResourceToCache()
308 if (resource->key().shareable() == Shareable::kYes) { in returnResourceToCache()
310 SkASSERT(fResourceMap.find(resource->key())); in returnResourceToCache()
312 SkDEBUGCODE(resource->fNonShareableInCache = true;) in returnResourceToCache()
313 resource->setLabel("Scratch"); in returnResourceToCache()
314 fResourceMap.insert(resource->key(), resource); in returnResourceToCache()
315 if (resource->budgeted() == skgpu::Budgeted::kNo) { in returnResourceToCache()
316 resource->makeBudgeted(); in returnResourceToCache()
317 fBudgetedBytes += resource->gpuMemorySize(); in returnResourceToCache()
322 if (resource->budgeted() == skgpu::Budgeted::kYes) { in returnResourceToCache()
323 size_t oldSize = resource->gpuMemorySize(); in returnResourceToCache()
324 resource->updateGpuMemorySize(); in returnResourceToCache()
325 if (oldSize != resource->gpuMemorySize()) { in returnResourceToCache()
327 fBudgetedBytes += resource->gpuMemorySize(); in returnResourceToCache()
331 // If we weren't using multiple threads, it is ok to assume a resource that isn't purgeable must in returnResourceToCache()
333 // threads, it is possible that a resource became purgeable while we are in the middle of in returnResourceToCache()
334 // returning resources. For example, a resource could have 1 usage and 1 command buffer ref. We in returnResourceToCache()
335 // then unref the usage which puts the resource in the return queue. Then the ResourceCache in returnResourceToCache()
336 // thread locks the ReturnQueue as it returns the Resource. At this same time another thread in returnResourceToCache()
337 // unrefs the command buffer usage but can't add the Resource to the ReturnQueue as it is in returnResourceToCache()
339 // Resource (from the kUsage ref) to return it to the cache it will look like it is purgeable in returnResourceToCache()
340 // since all refs are zero. Thus we will move the Resource from the non purgeable to purgeable in returnResourceToCache()
341 // queue. Then later when we return the command buffer ref, the Resource will have already been in returnResourceToCache()
343 if (!resource->isPurgeable() || this->inPurgeableQueue(resource)) { in returnResourceToCache()
348 this->setResourceTimestamp(resource, this->getNextTimestamp()); in returnResourceToCache()
350 this->removeFromNonpurgeableArray(resource); in returnResourceToCache()
352 if (resource->shouldDeleteASAP() == Resource::DeleteASAP::kYes) { in returnResourceToCache()
353 this->purgeResource(resource); in returnResourceToCache()
355 resource->updateAccessTime(); in returnResourceToCache()
356 fPurgeableQueue.insert(resource); in returnResourceToCache()
357 fPurgeableBytes += resource->gpuMemorySize(); in returnResourceToCache()
362 void ResourceCache::addToNonpurgeableArray(Resource* resource) { in addToNonpurgeableArray() argument
364 *fNonpurgeableResources.append() = resource; in addToNonpurgeableArray()
365 *resource->accessCacheIndex() = index; in addToNonpurgeableArray()
368 void ResourceCache::removeFromNonpurgeableArray(Resource* resource) { in removeFromNonpurgeableArray() argument
369 int* index = resource->accessCacheIndex(); in removeFromNonpurgeableArray()
372 Resource* tail = *(fNonpurgeableResources.end() - 1); in removeFromNonpurgeableArray()
373 SkASSERT(fNonpurgeableResources[*index] == resource); in removeFromNonpurgeableArray()
380 void ResourceCache::removeFromPurgeableQueue(Resource* resource) { in removeFromPurgeableQueue() argument
381 fPurgeableQueue.remove(resource); in removeFromPurgeableQueue()
382 fPurgeableBytes -= resource->gpuMemorySize(); in removeFromPurgeableQueue()
384 // flag for whether the Resource has been purged from the cache or not. So we need to make sure in removeFromPurgeableQueue()
386 *resource->accessCacheIndex() = -1; in removeFromPurgeableQueue()
389 bool ResourceCache::inPurgeableQueue(Resource* resource) const { in inPurgeableQueue()
390 SkASSERT(this->isInCache(resource)); in inPurgeableQueue()
391 int index = *resource->accessCacheIndex(); in inPurgeableQueue()
392 if (index < fPurgeableQueue.count() && fPurgeableQueue.at(index) == resource) { in inPurgeableQueue()
398 void ResourceCache::purgeResource(Resource* resource) { in purgeResource() argument
399 SkASSERT(resource->isPurgeable()); in purgeResource()
402 "size", resource->gpuMemorySize()); in purgeResource()
404 fResourceMap.remove(resource->key(), resource); in purgeResource()
406 if (resource->shouldDeleteASAP() == Resource::DeleteASAP::kNo) { in purgeResource()
407 SkASSERT(this->inPurgeableQueue(resource)); in purgeResource()
408 this->removeFromPurgeableQueue(resource); in purgeResource()
410 SkASSERT(!this->isInCache(resource)); in purgeResource()
413 fBudgetedBytes -= resource->gpuMemorySize(); in purgeResource()
414 resource->unrefCache(); in purgeResource()
427 Resource* resource = fPurgeableQueue.peek(); in purgeAsNeeded() local
428 SkASSERT(!resource->wasDestroyed()); in purgeAsNeeded()
429 SkASSERT(fResourceMap.find(resource->key())); in purgeAsNeeded()
431 if (resource->timestamp() == kMaxTimestamp) { in purgeAsNeeded()
432 // If we hit a resource that is at kMaxTimestamp, then we've hit the part of the in purgeAsNeeded()
435 SkASSERT(resource->gpuMemorySize() == 0); in purgeAsNeeded()
439 this->purgeResource(resource); in purgeAsNeeded()
474 SkTDArray<Resource*> resourcesToPurge; in purgeResources()
476 Resource* resource = fPurgeableQueue.at(i); in purgeResources() local
478 const skgpu::StdSteadyClock::time_point resourceTime = resource->lastAccessTime(); in purgeResources()
483 SkASSERT(resource->isPurgeable()); in purgeResources()
484 *resourcesToPurge.append() = resource; in purgeResources()
510 SkTDArray<Resource*> sortedPurgeableResources; in getNextTimestamp()
533 // Correct the index in the nonpurgeable array stored on the resource post-sort. in getNextTimestamp()
563 void ResourceCache::setResourceTimestamp(Resource* resource, uint32_t timestamp) { in setResourceTimestamp() argument
565 if (resource->gpuMemorySize() == 0) { in setResourceTimestamp()
568 resource->setTimestamp(timestamp); in setResourceTimestamp()
576 // purgeable queue). However, the Resource's own ref counts are used to report its purgeable in dumpMemoryStatistics()
595 const GraphiteResourceKey& ResourceCache::MapTraits::GetKey(const Resource& r) { in GetKey()
603 bool ResourceCache::CompareTimestamp(Resource* const& a, Resource* const& b) { in CompareTimestamp()
607 int* ResourceCache::AccessResourceIndex(Resource* const& res) { in AccessResourceIndex()
613 // Reduce the frequency of validations for large resource counts. in validate()
634 void update(Resource* resource) { in validate()
635 const GraphiteResourceKey& key = resource->key(); in validate()
639 SkASSERT(resource->hasCacheRef()); in validate()
643 SkASSERT(resource->ownership() == Ownership::kOwned); in validate()
650 if (resource->isUsableAsScratch()) { in validate()
652 SkASSERT(!resource->hasUsageRef()); in validate()
654 SkASSERT(fResourceMap->has(resource, key)); in validate()
655 SkASSERT(resource->budgeted() == skgpu::Budgeted::kYes); in validate()
657 SkASSERT(!fResourceMap->has(resource, key)); in validate()
661 SkASSERT(fResourceMap->has(resource, key)); in validate()
662 SkASSERT(resource->budgeted() == skgpu::Budgeted::kYes); in validate()
665 if (resource->budgeted() == skgpu::Budgeted::kYes) { in validate()
666 fBudgetedBytes += resource->gpuMemorySize(); in validate()
669 if (resource->gpuMemorySize() == 0) { in validate()
670 SkASSERT(resource->timestamp() == kMaxTimestamp); in validate()
672 SkASSERT(resource->timestamp() < kMaxTimestamp); in validate()
675 int index = *resource->accessCacheIndex(); in validate()
676 if (index < fPurgeableQueue->count() && fPurgeableQueue->at(index) == resource) { in validate()
677 SkASSERT(resource->isPurgeable()); in validate()
678 fPurgeableBytes += resource->gpuMemorySize(); in validate()
685 fResourceMap.foreach([&](const Resource& resource) { in validate() argument
686 SkASSERT(resource.isUsableAsScratch() || resource.key().shareable() == Shareable::kYes); in validate()
687 SkASSERT(resource.budgeted() == skgpu::Budgeted::kYes); in validate()
694 // we won't put a Resource into that queue unless all refs are zero. Thus there is no way for in validate()
695 // that resource to be made non-purgeable without going through the cache (which will switch in validate()
701 // queue yet. Its also possible that Resource hasn't been added to the ReturnQueue yet (thread in validate()
733 bool ResourceCache::isInCache(const Resource* resource) const { in isInCache()
734 int index = *resource->accessCacheIndex(); in isInCache()
738 if (index < fPurgeableQueue.count() && fPurgeableQueue.at(index) == resource) { in isInCache()
741 if (index < fNonpurgeableResources.size() && fNonpurgeableResources[index] == resource) { in isInCache()
744 SkDEBUGFAIL("Resource index should be -1 or the resource should be in the cache."); in isInCache()
756 Resource* ResourceCache::topOfPurgeableQueue() { in topOfPurgeableQueue()